Compare commits
2 commits
b5a0c61dd3
...
8a932d8759
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8a932d8759 | ||
![]() |
d5e6e4a19c |
40 changed files with 5718 additions and 631 deletions
130
doc/ai_cds_slides.md
Normal file
130
doc/ai_cds_slides.md
Normal file
|
@ -0,0 +1,130 @@
|
|||
# AI-CDS: Revolutionizing Software Development with AI
|
||||
|
||||
## 1. Title Slide
|
||||
### Title: AI-CDS: The Future of Code Development
|
||||
### Subtitle: Leveraging AI for Interface-Driven, Behavior-Driven, and Test-Driven Development
|
||||
- Presented by: [Your Name or Organization]
|
||||
- Date: [Insert Date]
|
||||
|
||||
## 2. Introduction
|
||||
### Slide Content
|
||||
#### What is AI-CDS?
|
||||
- AI-CDS stands for AI-driven Code Specification.
|
||||
- A methodology that integrates Interface-Driven Development (IDD), Behavior-Driven Development (BDD), Test-Driven Development (TDD), and Agile principles.
|
||||
|
||||
#### Why AI-CDS?
|
||||
- Bridges the gap between human creativity and AI efficiency.
|
||||
- Addresses the increasing complexity of software systems.
|
||||
- Aims for cross-platform compatibility, scalability, and maintainability.
|
||||
|
||||
### Visuals
|
||||
- A graphic showing AI at the center of IDD, BDD, TDD, and Agile.
|
||||
- A simplified flowchart of a traditional vs. AI-driven development pipeline.
|
||||
|
||||
## 3. The Core Principles of AI-CDS
|
||||
### Slide Content
|
||||
#### Interface-Driven Development (IDD):
|
||||
- Define clear contracts (interfaces) between components.
|
||||
- Promotes modularity and reusability.
|
||||
|
||||
#### Behavior-Driven Development (BDD):
|
||||
- Focus on user stories and desired behaviors.
|
||||
- Ensures alignment between technical implementation and business goals.
|
||||
|
||||
#### Test-Driven Development (TDD):
|
||||
- Automate the generation of unit tests.
|
||||
- Guarantees code correctness from the start.
|
||||
|
||||
#### Agile Development:
|
||||
- Iterative and adaptive, allowing for rapid changes and feedback.
|
||||
|
||||
### Visuals
|
||||
- Icons representing each principle with a brief description.
|
||||
- Examples of how these principles integrate into AI-CDS.
|
||||
|
||||
## 4. The Role of AI in AI-CDS
|
||||
### Slide Content
|
||||
- **Design Phase:** AI recommends designs and generates skeleton code.
|
||||
- **Development Phase:** AI generates functional code from interfaces and behaviors.
|
||||
- **Testing Phase:** AI creates and runs unit tests, refining code based on results.
|
||||
- **Refinement Phase:** AI optimizes code for performance, maintainability, and readability.
|
||||
|
||||
### Visuals
|
||||
- A timeline or pipeline with AI tasks at each stage.
|
||||
- Examples of AI tools like GPT models for code generation.
|
||||
|
||||
## 5. Workflow Example
|
||||
### Slide Content
|
||||
#### Step-by-Step Workflow:
|
||||
1. Define interfaces (e.g., AuthService, UserRepository).
|
||||
2. Use AI to generate code implementations.
|
||||
3. AI generates tests for predefined behaviors.
|
||||
4. Refine code through iterations based on test results.
|
||||
5. Finalize and deploy.
|
||||
|
||||
### Visuals
|
||||
- A workflow diagram illustrating the steps.
|
||||
- Before-and-after comparisons of AI-driven vs. manual workflows.
|
||||
|
||||
## 6. Benefits of AI-CDS
|
||||
### Slide Content
|
||||
- **Speed:** Rapid code generation and testing.
|
||||
- **Quality:** AI-generated code adheres to best practices and passes comprehensive tests.
|
||||
- **Cross-Platform:** Consistent output across multiple platforms.
|
||||
- **Cost Efficiency:** Reduces manual labor and errors.
|
||||
|
||||
### Visuals
|
||||
- A bar chart comparing time/cost savings between traditional development and AI-CDS.
|
||||
- Testimonials or case studies showcasing measurable benefits.
|
||||
|
||||
## 7. Challenges and Mitigation
|
||||
### Slide Content
|
||||
#### Challenges:
|
||||
- AI misinterpreting ambiguous requirements.
|
||||
- Maintaining AI-generated code for long-term projects.
|
||||
- Tool integration into existing workflows.
|
||||
|
||||
#### Mitigation Strategies:
|
||||
- Employ a human-in-the-loop approach.
|
||||
- Provide detailed specifications.
|
||||
- Use version control and refactoring tools for maintainability.
|
||||
|
||||
### Visuals
|
||||
- A problem/solution table.
|
||||
- Infographic showcasing "Human-in-the-Loop" interaction.
|
||||
|
||||
## 8. Future of AI-CDS
|
||||
### Slide Content
|
||||
#### What's Next?
|
||||
- Enhanced AI models for context-aware code generation.
|
||||
- Predictive debugging and runtime optimizations.
|
||||
- Wider adoption across industries and languages.
|
||||
|
||||
#### Community Impact:
|
||||
- Encourage open-source collaboration.
|
||||
- Push for community standards (e.g., Dart FIG).
|
||||
|
||||
### Visuals
|
||||
- Conceptual visualizations of future AI capabilities.
|
||||
- A roadmap for AI-CDS adoption and evolution.
|
||||
|
||||
## 9. Call to Action
|
||||
### Slide Content
|
||||
#### Get Involved:
|
||||
- Explore our specification and tools.
|
||||
- Join the community to shape the future of AI-CDS.
|
||||
|
||||
#### Contact Information:
|
||||
- Website, email, GitHub repository link.
|
||||
|
||||
### Visuals
|
||||
- QR codes linking to relevant resources.
|
||||
- Icons for collaboration platforms (e.g., Slack, GitHub).
|
||||
|
||||
## 10. Q&A Slide
|
||||
### Slide Content
|
||||
> "Thank you for your attention!"
|
||||
> "We welcome your questions and feedback."
|
||||
|
||||
### Visuals
|
||||
- Minimalist design with contact info repeated.
|
128
doc/ai_cds_specification.md
Normal file
128
doc/ai_cds_specification.md
Normal file
|
@ -0,0 +1,128 @@
|
|||
# 1. Introduction to AI-CDS
|
||||
|
||||
The AI-CDS (AI-driven Code Specification) is a cutting-edge approach to software development that incorporates AI-driven automation at every stage of the development lifecycle. It integrates concepts from Interface-Driven Development (IDD), Behavior-Driven Development (BDD), Test-Driven Development (TDD), and Agile Methodologies to create a streamlined, efficient, and high-quality approach to code generation, testing, and refinement.
|
||||
|
||||
AI-CDS leverages AI tools to generate highly optimized code, test cases, and refinements based on predefined interfaces and behaviors. This methodology enables teams to focus on the core logic and design of their systems, while AI handles the repetitive and time-consuming tasks. Human oversight remains integral to validate the outputs, ensuring correctness and adhering to specific project requirements.
|
||||
|
||||
# 2. The Core Principles of AI-CDS
|
||||
|
||||
## Interface-Driven Development (IDD)
|
||||
|
||||
Interface-Driven Development (IDD) is at the heart of AI-CDS. Instead of diving directly into code implementation, developers define interfaces that describe the expected behavior and structure of components. These interfaces serve as contracts between different parts of the system. The AI then generates the code to implement these interfaces, ensuring that the resulting system is modular and can easily adapt to future changes.
|
||||
|
||||
In practice, defining interfaces early helps achieve:
|
||||
|
||||
- Decoupling: Each component of the system works independently, allowing for easier modifications and scaling.
|
||||
- Reusability: Reusable components are easier to create since they are abstracted by their interfaces.
|
||||
|
||||
## Behavior-Driven Development (BDD)
|
||||
|
||||
BDD allows AI-CDS to focus on user stories and expected behaviors. By defining desired behaviors upfront, such as how a user interacts with a system, AI can generate code that closely matches business requirements. BDD also ensures that the resulting code meets not just technical specifications but also the business needs, increasing alignment between developers, stakeholders, and end-users.
|
||||
|
||||
Behavior definition enables:
|
||||
|
||||
- Improved communication: BDD bridges the gap between developers and non-technical stakeholders by emphasizing how software should behave from the user's perspective.
|
||||
- Predictability: By defining behavior early, development becomes more predictable as the system can be easily tested against expected outcomes.
|
||||
|
||||
## Test-Driven Development (TDD)
|
||||
|
||||
Incorporating TDD within AI-CDS ensures that AI-generated code is thoroughly tested and validated against predefined behaviors. Once the interfaces and behaviors are defined, the AI system can generate unit tests based on these criteria. It can also continuously adapt tests as the code evolves, ensuring that no regressions or issues are introduced in later stages of development.
|
||||
|
||||
Key benefits of integrating TDD include:
|
||||
|
||||
- Automated testing: The system can automatically run tests as soon as code changes are made, ensuring the codebase remains robust.
|
||||
- Early detection of issues: Problems can be identified early in the process, reducing the cost and time of fixing bugs.
|
||||
|
||||
## Agile Methodology
|
||||
|
||||
AI-CDS takes full advantage of Agile principles to ensure that the development process remains flexible and iterative. By breaking down development into sprints, AI tools can quickly iterate on code, receive human feedback, and refine it. Scrum or Kanban frameworks provide the structure for managing tasks and monitoring progress, ensuring continuous delivery and rapid adaptation.
|
||||
|
||||
Agile integration offers:
|
||||
|
||||
- Iterative improvement: The software continuously evolves based on feedback, allowing for frequent releases and adjustments.
|
||||
- Flexibility: Agile accommodates changing requirements without disrupting the development flow.
|
||||
|
||||
# 3. AI's Role in Each Phase
|
||||
|
||||
## Design Phase
|
||||
|
||||
In the design phase, AI tools help define the system's architecture by recommending designs and code snippets. AI can interpret high-level descriptions and help generate the skeleton code or architectural patterns necessary to build a scalable and maintainable system.
|
||||
|
||||
For example, AI could suggest using specific design patterns like Factory or Strategy based on the system requirements. This can be particularly useful for:
|
||||
|
||||
- Automating design decisions based on best practices.
|
||||
- Ensuring the design is modular and easily extendable.
|
||||
|
||||
## Development Phase
|
||||
|
||||
During the development phase, AI plays an active role in generating the bulk of the application's code. Based on the interfaces and behaviors defined earlier, AI systems like Codex or GPT-based tools automatically generate code snippets and full class implementations. Developers can guide and fine-tune the code, allowing AI to take care of repetitive tasks, such as:
|
||||
|
||||
- Data access logic.
|
||||
- Boilerplate code.
|
||||
- Common business logic implementations.
|
||||
|
||||
## Testing Phase
|
||||
|
||||
In the testing phase, AI-CDS helps by generating unit tests based on the behaviors defined earlier. It also automatically runs tests on the generated code to check for correctness and behavior compliance. AI can refine tests as code evolves, ensuring test coverage remains complete.
|
||||
|
||||
By utilizing AI, the testing process becomes more efficient:
|
||||
|
||||
- Automated test generation: AI automatically creates tests that align with business behaviors.
|
||||
- Dynamic testing adjustments: The system adjusts tests as new behaviors are added or modified.
|
||||
|
||||
## Refinement Phase
|
||||
|
||||
As development progresses, AI tools continuously refine the generated code based on feedback. AI can:
|
||||
|
||||
- Suggest optimizations for performance or readability.
|
||||
- Refactor code to enhance maintainability.
|
||||
- Identify and resolve issues based on test results and user feedback.
|
||||
|
||||
In this phase, AI supports human developers by ensuring code quality, correctness, and alignment with evolving requirements.
|
||||
|
||||
# 4. Benefits of AI-CDS
|
||||
|
||||
- Speed: AI reduces the time spent on repetitive tasks, such as writing boilerplate code or generating unit tests, speeding up the overall development process.
|
||||
- Consistency: AI ensures that code follows a consistent pattern and adheres to best practices. This reduces the likelihood of bugs due to inconsistent coding styles.
|
||||
- Quality: AI can generate high-quality, optimized code and ensure that it is thoroughly tested, reducing the chances of defects in the final product.
|
||||
- Cross-Platform Compatibility: AI-CDS ensures that the generated code works consistently across multiple platforms (e.g., mobile, web, desktop) by adhering to interface contracts and abstracting platform-specific concerns.
|
||||
|
||||
# 5. Example Workflow in AI-CDS
|
||||
|
||||
Here's an example of how a project would flow through AI-CDS:
|
||||
|
||||
1. Define Interfaces: The team defines a set of interfaces representing the core business logic, such as UserRepository, AuthService, etc.
|
||||
2. Generate Code: Using AI tools, the system generates code that adheres to these interfaces and incorporates the desired business behaviors.
|
||||
3. Generate Unit Tests: AI automatically generates unit tests to validate that the code behaves as expected, based on BDD specifications.
|
||||
4. Run Tests and Refine: AI runs the tests, identifies any issues, and refines the generated code. Developers provide feedback, and AI fine-tunes the code.
|
||||
5. Deploy: Once the code is fully tested and refined, it is ready for deployment.
|
||||
|
||||
# 6. Challenges and Mitigation Strategies
|
||||
|
||||
## Complexity in AI Interpretation
|
||||
|
||||
One challenge with AI-driven development is the risk of AI tools misinterpreting ambiguous or incomplete specifications. This can lead to misaligned or incorrect code. To mitigate this, a human-in-the-loop approach is essential:
|
||||
|
||||
- Human oversight ensures that AI-generated code is reviewed and refined.
|
||||
- Clear specifications and documentation guide AI tools, reducing the risk of misinterpretation.
|
||||
|
||||
## Maintaining AI-Generated Code
|
||||
|
||||
As AI-generated code evolves, human developers must ensure it remains maintainable:
|
||||
|
||||
- Version control systems and refactoring tools will help maintain the generated code.
|
||||
- Code guidelines ensure that AI-generated code adheres to best practices and remains easy to maintain.
|
||||
|
||||
## Tooling and Integration
|
||||
|
||||
Integrating AI-CDS with existing tools like IDEs, CI/CD pipelines, and version control systems requires careful planning and customization:
|
||||
|
||||
- Custom plugins or integrations may be needed to facilitate smooth collaboration between AI tools and traditional development environments.
|
||||
|
||||
# 7. The Future of AI-CDS
|
||||
|
||||
The future of AI-CDS is bright, with continued advancements in AI technologies:
|
||||
|
||||
- Enhanced language models (e.g., GPT-4, Codex) will provide even more accurate and context-aware code generation.
|
||||
- Predictive debugging: AI will become better at predicting bugs based on historical data, reducing the need for manual debugging.
|
||||
- Dynamic code optimization: AI will learn to optimize code for performance dynamically based on real-time data, reducing human intervention.
|
5
doc/directory_feeds
Normal file
5
doc/directory_feeds
Normal file
|
@ -0,0 +1,5 @@
|
|||
mirrors.dart
|
||||
/home/platform/Devboxes/sdk/sdk/lib/mirrors
|
||||
mirrors.h mirrors.cc
|
||||
/home/platform/Devboxes/sdk/runtime/lib
|
||||
/home/platform/Devboxes/fake_reflection
|
201
doc/reflection_ai_cds_alignment.md
Normal file
201
doc/reflection_ai_cds_alignment.md
Normal file
|
@ -0,0 +1,201 @@
|
|||
# Reflection System Alignment with AI-CDS Principles
|
||||
|
||||
## 1. Interface-Driven Development (IDD) Alignment
|
||||
|
||||
### Core Principles
|
||||
- Our reflection system is built around explicit interface contracts
|
||||
- Uses registration-based approach for type information
|
||||
- Promotes modularity through clear component boundaries
|
||||
|
||||
### Implementation Strategy
|
||||
1. Interface Definition
|
||||
- Define clear contracts for reflection capabilities
|
||||
- Separate core reflection interfaces from implementation
|
||||
- Use interface segregation for specialized reflection needs
|
||||
|
||||
2. Component Boundaries
|
||||
- Separate metadata handling from runtime reflection
|
||||
- Isolate platform-specific code from core reflection
|
||||
- Clear separation between registration and resolution
|
||||
|
||||
## 2. Behavior-Driven Development (BDD) Alignment
|
||||
|
||||
### Core Behaviors
|
||||
1. Type Resolution
|
||||
- Discover and validate type information
|
||||
- Handle constructor parameters
|
||||
- Manage type relationships
|
||||
|
||||
2. Instance Creation
|
||||
- Create instances with dependencies
|
||||
- Handle constructor overloads
|
||||
- Manage lifecycle
|
||||
|
||||
3. Member Access
|
||||
- Property get/set operations
|
||||
- Method invocation
|
||||
- Field access control
|
||||
|
||||
### Implementation Approach
|
||||
- Define behaviors before implementation
|
||||
- Use behavior specifications to drive API design
|
||||
- Ensure consistent behavior across platforms
|
||||
|
||||
## 3. Test-Driven Development (TDD) Alignment
|
||||
|
||||
### Test Categories
|
||||
1. Unit Tests
|
||||
- Type reflection accuracy
|
||||
- Instance creation scenarios
|
||||
- Member access patterns
|
||||
- Error handling cases
|
||||
|
||||
2. Integration Tests
|
||||
- Container integration
|
||||
- Framework compatibility
|
||||
- Cross-platform behavior
|
||||
|
||||
3. Performance Tests
|
||||
- Resolution speed
|
||||
- Memory usage
|
||||
- Scalability metrics
|
||||
|
||||
### Test-First Approach
|
||||
- Write tests before implementation
|
||||
- Use tests to validate cross-platform behavior
|
||||
- Ensure consistent error handling
|
||||
|
||||
## 4. AI Integration Points
|
||||
|
||||
### Code Generation
|
||||
1. Registration Code
|
||||
- AI generates type registration code
|
||||
- Handles complex type relationships
|
||||
- Manages metadata generation
|
||||
|
||||
2. Test Generation
|
||||
- Creates comprehensive test suites
|
||||
- Generates edge cases
|
||||
- Validates cross-platform behavior
|
||||
|
||||
### Optimization
|
||||
1. Performance
|
||||
- AI suggests optimization strategies
|
||||
- Identifies bottlenecks
|
||||
- Recommends caching strategies
|
||||
|
||||
2. Memory Usage
|
||||
- Optimizes metadata storage
|
||||
- Reduces runtime overhead
|
||||
- Manages resource cleanup
|
||||
|
||||
## 5. Cross-Platform Considerations
|
||||
|
||||
### Platform Independence
|
||||
1. Core Features
|
||||
- Pure Dart implementation
|
||||
- No platform-specific dependencies
|
||||
- Consistent behavior guarantee
|
||||
|
||||
2. Platform Optimization
|
||||
- Platform-specific optimizations where needed
|
||||
- Fallback mechanisms for unsupported features
|
||||
- Performance tuning per platform
|
||||
|
||||
### Compatibility Layer
|
||||
1. Web Platform
|
||||
- Handle JavaScript interop
|
||||
- Manage tree-shaking
|
||||
- Optimize for browser environment
|
||||
|
||||
2. Native Platforms
|
||||
- Optimize for AOT compilation
|
||||
- Handle platform restrictions
|
||||
- Manage memory efficiently
|
||||
|
||||
## 6. Laravel Framework Support
|
||||
|
||||
### Container Features
|
||||
1. Service Location
|
||||
- Type-based resolution
|
||||
- Named instance management
|
||||
- Contextual binding
|
||||
|
||||
2. Dependency Injection
|
||||
- Constructor injection
|
||||
- Method injection
|
||||
- Property injection
|
||||
|
||||
### Framework Integration
|
||||
1. Service Providers
|
||||
- Registration automation
|
||||
- Lifecycle management
|
||||
- Deferred loading support
|
||||
|
||||
2. Middleware
|
||||
- Dependency resolution
|
||||
- Parameter injection
|
||||
- Pipeline handling
|
||||
|
||||
## 7. AI-CDS Workflow Integration
|
||||
|
||||
### Development Workflow
|
||||
1. Design Phase
|
||||
- AI assists in interface design
|
||||
- Generates reflection contracts
|
||||
- Suggests optimization strategies
|
||||
|
||||
2. Implementation Phase
|
||||
- Generates registration code
|
||||
- Creates test suites
|
||||
- Provides optimization suggestions
|
||||
|
||||
3. Testing Phase
|
||||
- Validates implementation
|
||||
- Generates test cases
|
||||
- Identifies edge cases
|
||||
|
||||
4. Refinement Phase
|
||||
- Optimizes performance
|
||||
- Improves memory usage
|
||||
- Enhances error handling
|
||||
|
||||
### Continuous Improvement
|
||||
1. Feedback Loop
|
||||
- Performance metrics
|
||||
- Usage patterns
|
||||
- Error scenarios
|
||||
|
||||
2. Optimization
|
||||
- AI-driven improvements
|
||||
- Platform-specific optimizations
|
||||
- Resource usage optimization
|
||||
|
||||
## 8. Future Extensibility
|
||||
|
||||
### Enhancement Areas
|
||||
1. Type System
|
||||
- Enhanced generic support
|
||||
- Better type inference
|
||||
- Improved type safety
|
||||
|
||||
2. Performance
|
||||
- Smarter caching
|
||||
- Better memory management
|
||||
- Reduced overhead
|
||||
|
||||
3. Framework Support
|
||||
- Additional framework features
|
||||
- Extended container capabilities
|
||||
- Enhanced middleware support
|
||||
|
||||
### AI Evolution
|
||||
1. Code Generation
|
||||
- More accurate registration code
|
||||
- Better test coverage
|
||||
- Improved optimization suggestions
|
||||
|
||||
2. Analysis
|
||||
- Enhanced performance analysis
|
||||
- Better bottleneck detection
|
||||
- Improved optimization recommendations
|
89
doc/reflection_docs_index.md
Normal file
89
doc/reflection_docs_index.md
Normal file
|
@ -0,0 +1,89 @@
|
|||
# Reflection System Documentation Index
|
||||
|
||||
## Core Documentation
|
||||
|
||||
### [System Overview](reflection_system_overview.md)
|
||||
- Complete system architecture based on Dart mirrors API
|
||||
- Implementation strategy
|
||||
- Cross-platform support
|
||||
- Success metrics
|
||||
|
||||
### [Implementation Gaps](reflection_implementation_gaps.md)
|
||||
- Current status vs Dart mirrors API
|
||||
- Missing features analysis
|
||||
- Priority implementation areas
|
||||
- Next steps
|
||||
|
||||
### [Implementation Plan](reflection_implementation_plan.md)
|
||||
- Detailed implementation phases
|
||||
- Core mirror system design
|
||||
- Testing strategy
|
||||
- Timeline
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
### [AI-CDS Specification](ai_cds_specification.md)
|
||||
- AI-driven development methodology
|
||||
- Core principles
|
||||
- Development workflow
|
||||
- Best practices
|
||||
|
||||
### [AI-CDS Presentation](ai_cds_slides.md)
|
||||
- Visual presentation of AI-CDS
|
||||
- Implementation examples
|
||||
- Future roadmap
|
||||
- Best practices
|
||||
|
||||
## API Implementation Status
|
||||
|
||||
### Core Mirrors
|
||||
- [ ] MirrorSystem
|
||||
- [ ] DeclarationMirror
|
||||
- [ ] ObjectMirror
|
||||
- [ ] TypeMirror
|
||||
|
||||
### Type System
|
||||
- [ ] ClassMirror
|
||||
- [ ] TypeVariableMirror
|
||||
- [ ] MethodMirror
|
||||
- [ ] VariableMirror
|
||||
|
||||
### Library Support
|
||||
- [ ] LibraryMirror
|
||||
- [ ] LibraryDependencyMirror
|
||||
- [ ] IsolateMirror
|
||||
- [ ] SourceLocation
|
||||
|
||||
## Using This Documentation
|
||||
|
||||
### For Implementers
|
||||
1. Start with System Overview
|
||||
2. Review Implementation Gaps
|
||||
3. Follow Implementation Plan
|
||||
4. Track progress
|
||||
|
||||
### For Contributors
|
||||
1. Understand Dart mirrors API alignment
|
||||
2. Review current gaps
|
||||
3. Follow implementation plan
|
||||
4. Maintain documentation
|
||||
|
||||
### For Project Managers
|
||||
1. Monitor implementation status
|
||||
2. Review progress
|
||||
3. Track success metrics
|
||||
4. Plan resources
|
||||
|
||||
## Documentation Standards
|
||||
- Keep aligned with Dart mirrors API
|
||||
- Maintain implementation status
|
||||
- Document design decisions
|
||||
- Track cross-platform considerations
|
||||
|
||||
## Navigation Tips
|
||||
- Use links to move between documents
|
||||
- Check Implementation Gaps for current status
|
||||
- Follow Implementation Plan for next steps
|
||||
- Review System Overview for context
|
||||
|
||||
This index provides a central reference point for all reflection system documentation, focusing on our implementation of the Dart mirrors API.
|
186
doc/reflection_implementation_gaps.md
Normal file
186
doc/reflection_implementation_gaps.md
Normal file
|
@ -0,0 +1,186 @@
|
|||
# Reflection System Implementation Gap Analysis
|
||||
|
||||
## Current Implementation vs Dart Mirrors API
|
||||
|
||||
### 1. Mirror System Gaps
|
||||
|
||||
#### ✓ Implemented
|
||||
- Basic type reflection
|
||||
- Instance creation
|
||||
- Method invocation
|
||||
- Property access
|
||||
|
||||
#### 🔴 Missing
|
||||
- MirrorSystem as entry point
|
||||
- Library mirror support
|
||||
- Symbol handling
|
||||
- Isolate support
|
||||
- Complete type system (void, never types)
|
||||
|
||||
### 2. Core Mirrors Gaps
|
||||
|
||||
#### ✓ Implemented
|
||||
- Basic DeclarationMirror features
|
||||
- Simple metadata handling
|
||||
- Owner tracking
|
||||
- Privacy checking
|
||||
|
||||
#### 🔴 Missing
|
||||
- Complete DeclarationMirror hierarchy
|
||||
- Qualified name handling
|
||||
- Full metadata support
|
||||
- Source location support
|
||||
|
||||
### 3. Type System Gaps
|
||||
|
||||
#### ✓ Implemented
|
||||
- Basic type metadata
|
||||
- Constructor handling
|
||||
- Method reflection
|
||||
- Property reflection
|
||||
|
||||
#### 🔴 Missing
|
||||
- TypeMirror hierarchy
|
||||
- Generic type support
|
||||
- Type variable handling
|
||||
- Type relationship checking
|
||||
- Original declaration tracking
|
||||
|
||||
### 4. Object Mirror Gaps
|
||||
|
||||
#### ✓ Implemented
|
||||
- Basic method invocation
|
||||
- Property get/set
|
||||
- Instance creation
|
||||
- Type checking
|
||||
|
||||
#### 🔴 Missing
|
||||
- Symbol-based member access
|
||||
- Named argument support
|
||||
- Dynamic invocation
|
||||
- Delegate support
|
||||
|
||||
### 5. Cross-Platform Gaps
|
||||
|
||||
#### ✓ Implemented
|
||||
- Pure Dart implementation
|
||||
- Basic type handling
|
||||
- Platform-independent core
|
||||
|
||||
#### 🔴 Missing
|
||||
- Web platform optimizations
|
||||
- Native platform support
|
||||
- Tree-shaking compatibility
|
||||
- AOT compilation support
|
||||
|
||||
## Priority Implementation Areas
|
||||
|
||||
### 1. MirrorSystem (High Priority)
|
||||
```dart
|
||||
abstract class MirrorSystem {
|
||||
Map<Uri, LibraryMirror> get libraries;
|
||||
LibraryMirror findLibrary(Symbol libraryName);
|
||||
IsolateMirror get isolate;
|
||||
TypeMirror get dynamicType;
|
||||
TypeMirror get voidType;
|
||||
TypeMirror get neverType;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. TypeMirror System (High Priority)
|
||||
```dart
|
||||
abstract class TypeMirror implements DeclarationMirror {
|
||||
bool get hasReflectedType;
|
||||
Type get reflectedType;
|
||||
List<TypeVariableMirror> get typeVariables;
|
||||
List<TypeMirror> get typeArguments;
|
||||
bool get isOriginalDeclaration;
|
||||
TypeMirror get originalDeclaration;
|
||||
bool isSubtypeOf(TypeMirror other);
|
||||
bool isAssignableTo(TypeMirror other);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Library Support (Medium Priority)
|
||||
```dart
|
||||
abstract class LibraryMirror implements DeclarationMirror, ObjectMirror {
|
||||
Uri get uri;
|
||||
Map<Symbol, DeclarationMirror> get declarations;
|
||||
List<LibraryDependencyMirror> get libraryDependencies;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Method Mirror (Medium Priority)
|
||||
```dart
|
||||
abstract class MethodMirror implements DeclarationMirror {
|
||||
TypeMirror get returnType;
|
||||
List<ParameterMirror> get parameters;
|
||||
bool get isAbstract;
|
||||
bool get isRegularMethod;
|
||||
bool get isOperator;
|
||||
bool get isGetter;
|
||||
bool get isSetter;
|
||||
bool get isConstructor;
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Variable Mirror (Medium Priority)
|
||||
```dart
|
||||
abstract class VariableMirror implements DeclarationMirror {
|
||||
TypeMirror get type;
|
||||
bool get isStatic;
|
||||
bool get isFinal;
|
||||
bool get isConst;
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### Phase 1: Core System
|
||||
1. Implement MirrorSystem
|
||||
2. Complete DeclarationMirror hierarchy
|
||||
3. Add Symbol support
|
||||
4. Implement basic TypeMirror
|
||||
|
||||
### Phase 2: Type System
|
||||
1. Complete TypeMirror implementation
|
||||
2. Add generic support
|
||||
3. Implement type relationships
|
||||
4. Add type variables
|
||||
|
||||
### Phase 3: Library Support
|
||||
1. Implement LibraryMirror
|
||||
2. Add library dependencies
|
||||
3. Support library-level declarations
|
||||
4. Handle privacy scope
|
||||
|
||||
### Phase 4: Platform Support
|
||||
1. Add web optimizations
|
||||
2. Implement native support
|
||||
3. Handle AOT compilation
|
||||
4. Optimize performance
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
### 1. Unit Tests Needed
|
||||
- Mirror system tests
|
||||
- Type system tests
|
||||
- Library support tests
|
||||
- Method/variable tests
|
||||
- Cross-platform tests
|
||||
|
||||
### 2. Integration Tests Needed
|
||||
- Full reflection scenarios
|
||||
- Platform compatibility
|
||||
- Performance benchmarks
|
||||
- Memory usage tests
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Implement MirrorSystem as entry point
|
||||
2. Complete TypeMirror hierarchy
|
||||
3. Add Symbol support
|
||||
4. Begin library mirror support
|
||||
5. Add platform optimizations
|
||||
|
||||
This analysis shows the gaps between our current implementation and the Dart mirrors API. By following the mirrors API, we ensure our reflection system will provide familiar and comprehensive reflection capabilities while maintaining cross-platform support.
|
167
doc/reflection_implementation_plan.md
Normal file
167
doc/reflection_implementation_plan.md
Normal file
|
@ -0,0 +1,167 @@
|
|||
# Reflection System Implementation Plan
|
||||
|
||||
## Core Design
|
||||
Following the Dart mirrors API design while maintaining cross-platform compatibility.
|
||||
|
||||
### Mirror System
|
||||
```dart
|
||||
abstract class MirrorSystem {
|
||||
Map<Uri, LibraryMirror> get libraries;
|
||||
LibraryMirror findLibrary(Symbol libraryName);
|
||||
IsolateMirror get isolate;
|
||||
TypeMirror get dynamicType;
|
||||
TypeMirror get voidType;
|
||||
TypeMirror get neverType;
|
||||
}
|
||||
```
|
||||
|
||||
### Core Mirrors
|
||||
```dart
|
||||
abstract class Mirror {}
|
||||
|
||||
abstract class DeclarationMirror implements Mirror {
|
||||
Symbol get simpleName;
|
||||
Symbol get qualifiedName;
|
||||
DeclarationMirror? get owner;
|
||||
bool get isPrivate;
|
||||
bool get isTopLevel;
|
||||
List<InstanceMirror> get metadata;
|
||||
}
|
||||
|
||||
abstract class ObjectMirror implements Mirror {
|
||||
InstanceMirror invoke(Symbol memberName, List positionalArgs, [Map<Symbol, dynamic> namedArgs]);
|
||||
InstanceMirror getField(Symbol fieldName);
|
||||
InstanceMirror setField(Symbol fieldName, Object? value);
|
||||
}
|
||||
```
|
||||
|
||||
### Type System
|
||||
```dart
|
||||
abstract class TypeMirror implements DeclarationMirror {
|
||||
bool get hasReflectedType;
|
||||
Type get reflectedType;
|
||||
List<TypeVariableMirror> get typeVariables;
|
||||
List<TypeMirror> get typeArguments;
|
||||
bool get isOriginalDeclaration;
|
||||
TypeMirror get originalDeclaration;
|
||||
bool isSubtypeOf(TypeMirror other);
|
||||
bool isAssignableTo(TypeMirror other);
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Core Mirror System
|
||||
1. Basic Mirror interfaces
|
||||
- Mirror base class
|
||||
- DeclarationMirror
|
||||
- ObjectMirror
|
||||
- TypeMirror
|
||||
|
||||
2. Instance Reflection
|
||||
- InstanceMirror implementation
|
||||
- Method invocation
|
||||
- Field access
|
||||
- Constructor invocation
|
||||
|
||||
3. Type Reflection
|
||||
- ClassMirror implementation
|
||||
- Type information handling
|
||||
- Member reflection
|
||||
- Metadata support
|
||||
|
||||
### Phase 2: Type System
|
||||
1. Type Mirrors
|
||||
- TypeMirror implementation
|
||||
- TypeVariableMirror
|
||||
- Generic type support
|
||||
- Type relationships
|
||||
|
||||
2. Method Reflection
|
||||
- MethodMirror implementation
|
||||
- Parameter handling
|
||||
- Return type resolution
|
||||
- Invocation support
|
||||
|
||||
3. Field Reflection
|
||||
- VariableMirror implementation
|
||||
- Property access
|
||||
- Field metadata
|
||||
- Type checking
|
||||
|
||||
### Phase 3: Advanced Features
|
||||
1. Library Support
|
||||
- LibraryMirror implementation
|
||||
- Symbol resolution
|
||||
- Privacy handling
|
||||
- Library dependencies
|
||||
|
||||
2. Metadata System
|
||||
- Annotation support
|
||||
- Metadata reflection
|
||||
- Declaration scanning
|
||||
- Attribute handling
|
||||
|
||||
### Phase 4: Platform Support
|
||||
1. Web Platform
|
||||
- Tree shaking support
|
||||
- Minification handling
|
||||
- Browser optimizations
|
||||
- JS interop
|
||||
|
||||
2. Native Platforms
|
||||
- AOT compilation support
|
||||
- Native optimizations
|
||||
- Memory management
|
||||
- Performance tuning
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
1. Core Functionality
|
||||
- Mirror creation
|
||||
- Type reflection
|
||||
- Member access
|
||||
- Method invocation
|
||||
|
||||
2. Type System
|
||||
- Type relationships
|
||||
- Generic handling
|
||||
- Type variables
|
||||
- Type metadata
|
||||
|
||||
### Integration Tests
|
||||
1. System Tests
|
||||
- Full reflection scenarios
|
||||
- Cross-platform behavior
|
||||
- Edge cases
|
||||
- Error handling
|
||||
|
||||
2. Performance Tests
|
||||
- Memory usage
|
||||
- Operation speed
|
||||
- Resource management
|
||||
- Platform behavior
|
||||
|
||||
## Success Criteria
|
||||
|
||||
### Functional
|
||||
- Complete mirrors API implementation
|
||||
- Cross-platform compatibility
|
||||
- Full type system support
|
||||
- Metadata handling
|
||||
|
||||
### Technical
|
||||
- Matches Dart mirrors behavior
|
||||
- Efficient memory usage
|
||||
- Fast reflection operations
|
||||
- Platform optimizations
|
||||
|
||||
## Timeline
|
||||
- Phase 1: 3 weeks
|
||||
- Phase 2: 3 weeks
|
||||
- Phase 3: 2 weeks
|
||||
- Phase 4: 2 weeks
|
||||
- Total: 10 weeks
|
||||
|
||||
This plan focuses on implementing the core Dart mirrors API while ensuring cross-platform compatibility and performance. By following the established mirrors API, we ensure our reflection system will be familiar to Dart developers and capable of supporting any use case that the original mirrors system supports.
|
161
doc/reflection_progress_tracking.md
Normal file
161
doc/reflection_progress_tracking.md
Normal file
|
@ -0,0 +1,161 @@
|
|||
# Reflection System Implementation Progress Tracking
|
||||
|
||||
## Overall Status
|
||||
- Start Date: [TBD]
|
||||
- Current Phase: Planning
|
||||
- Current Sprint: Pre-implementation
|
||||
- Overall Progress: Documentation Phase
|
||||
|
||||
## Phase 1: Core Container Support [Not Started]
|
||||
|
||||
### Sprint 1: Container Reflection Foundation
|
||||
#### Status: Not Started
|
||||
- [ ] ContainerReflector interface
|
||||
- [ ] DependencyResolver interface
|
||||
- [ ] ResolutionContext implementation
|
||||
- [ ] BindingContext implementation
|
||||
- [ ] Core tests implementation
|
||||
|
||||
#### AI Integration Status
|
||||
- [ ] Generated interface contracts review
|
||||
- [ ] Test scenario generation
|
||||
- [ ] Implementation pattern validation
|
||||
- [ ] Resolution path optimization
|
||||
|
||||
### Sprint 2: Metadata Enhancement
|
||||
#### Status: Not Started
|
||||
- [ ] Enhanced type information
|
||||
- [ ] Binding metadata support
|
||||
- [ ] Resolution path caching
|
||||
- [ ] Dependency relationship tracking
|
||||
- [ ] Performance optimization
|
||||
|
||||
## Phase 2: Framework Integration [Not Started]
|
||||
|
||||
### Sprint 3: Service Provider Support
|
||||
#### Status: Not Started
|
||||
- [ ] Provider reflection implementation
|
||||
- [ ] Service registration system
|
||||
- [ ] Provider lifecycle management
|
||||
- [ ] Deferred loading support
|
||||
|
||||
### Sprint 4: Method Injection
|
||||
#### Status: Not Started
|
||||
- [ ] Method resolution system
|
||||
- [ ] Parameter injection
|
||||
- [ ] Controller support
|
||||
- [ ] Middleware integration
|
||||
|
||||
## Phase 3: Advanced Features [Not Started]
|
||||
|
||||
### Sprint 5: Contextual Binding
|
||||
#### Status: Not Started
|
||||
- [ ] Context resolution system
|
||||
- [ ] Binding rules implementation
|
||||
- [ ] Context management
|
||||
- [ ] Binding optimization
|
||||
|
||||
### Sprint 6: Instance Scoping
|
||||
#### Status: Not Started
|
||||
- [ ] Scope management system
|
||||
- [ ] Instance tracking
|
||||
- [ ] Lifecycle management
|
||||
- [ ] Memory optimization
|
||||
|
||||
## Phase 4: Platform Optimization [Not Started]
|
||||
|
||||
### Sprint 7: Web Platform
|
||||
#### Status: Not Started
|
||||
- [ ] Tree shaking optimization
|
||||
- [ ] Browser performance tuning
|
||||
- [ ] Memory usage optimization
|
||||
- [ ] Web-specific features
|
||||
|
||||
### Sprint 8: Native Platforms
|
||||
#### Status: Not Started
|
||||
- [ ] AOT compilation support
|
||||
- [ ] Native platform optimization
|
||||
- [ ] Performance tuning
|
||||
- [ ] Platform-specific features
|
||||
|
||||
## Testing Progress
|
||||
|
||||
### Unit Tests
|
||||
#### Status: Not Started
|
||||
- [ ] Core reflection tests
|
||||
- [ ] Container feature tests
|
||||
- [ ] Framework integration tests
|
||||
- [ ] Platform-specific tests
|
||||
|
||||
### Integration Tests
|
||||
#### Status: Not Started
|
||||
- [ ] Framework compatibility tests
|
||||
- [ ] Cross-platform tests
|
||||
- [ ] Performance benchmark tests
|
||||
- [ ] Memory usage tests
|
||||
|
||||
## Documentation Progress
|
||||
|
||||
### Technical Documentation
|
||||
#### Status: In Progress
|
||||
- [x] AI-CDS alignment document
|
||||
- [x] Implementation gaps analysis
|
||||
- [x] Implementation plan
|
||||
- [ ] API documentation
|
||||
- [ ] Usage guidelines
|
||||
|
||||
### Framework Integration Documentation
|
||||
#### Status: Not Started
|
||||
- [ ] Laravel feature support guide
|
||||
- [ ] Platform-specific guidelines
|
||||
- [ ] Performance recommendations
|
||||
- [ ] Best practices guide
|
||||
|
||||
## Milestones
|
||||
|
||||
### Phase 1
|
||||
- [ ] Basic container reflection working
|
||||
- [ ] Dependency injection functional
|
||||
- [ ] Type resolution implemented
|
||||
- [ ] Core tests passing
|
||||
|
||||
### Phase 2
|
||||
- [ ] Service providers supported
|
||||
- [ ] Method injection working
|
||||
- [ ] Controller support implemented
|
||||
- [ ] Framework integration tests passing
|
||||
|
||||
### Phase 3
|
||||
- [ ] Contextual binding working
|
||||
- [ ] Instance scoping implemented
|
||||
- [ ] Advanced features tested
|
||||
- [ ] Performance targets met
|
||||
|
||||
### Phase 4
|
||||
- [ ] Web platform optimized
|
||||
- [ ] Native platforms supported
|
||||
- [ ] All tests passing
|
||||
- [ ] Documentation complete
|
||||
|
||||
## Current Blockers
|
||||
1. None - In planning phase
|
||||
|
||||
## Next Steps
|
||||
1. Begin Phase 1 implementation
|
||||
2. Set up CI/CD pipeline
|
||||
3. Implement core interfaces
|
||||
4. Start unit test development
|
||||
|
||||
## Performance Metrics
|
||||
- Resolution Speed: Not measured
|
||||
- Memory Usage: Not measured
|
||||
- Startup Time: Not measured
|
||||
- Runtime Overhead: Not measured
|
||||
|
||||
## Quality Metrics
|
||||
- Test Coverage: 0%
|
||||
- Code Quality: Not measured
|
||||
- Documentation Coverage: In progress
|
||||
- Performance Benchmarks: Not started
|
||||
|
||||
This tracking document will be updated as we progress through the implementation phases.
|
173
doc/reflection_system_overview.md
Normal file
173
doc/reflection_system_overview.md
Normal file
|
@ -0,0 +1,173 @@
|
|||
# Reflection System Overview
|
||||
|
||||
## Project Summary
|
||||
The reflection system implements the Dart mirrors API in a cross-platform compatible way. By following the established mirrors API design, we ensure our system provides familiar, comprehensive reflection capabilities while working across all Dart platforms. The implementation follows AI-CDS methodology to ensure high quality, maintainable, and efficient code.
|
||||
|
||||
## Core Architecture
|
||||
|
||||
### 1. Mirror System
|
||||
The central entry point following Dart's MirrorSystem design:
|
||||
```dart
|
||||
abstract class MirrorSystem {
|
||||
Map<Uri, LibraryMirror> get libraries;
|
||||
LibraryMirror findLibrary(Symbol libraryName);
|
||||
IsolateMirror get isolate;
|
||||
TypeMirror get dynamicType;
|
||||
TypeMirror get voidType;
|
||||
TypeMirror get neverType;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Core Mirrors
|
||||
The fundamental reflection capabilities:
|
||||
```dart
|
||||
abstract class Mirror {}
|
||||
|
||||
abstract class DeclarationMirror implements Mirror {
|
||||
Symbol get simpleName;
|
||||
Symbol get qualifiedName;
|
||||
DeclarationMirror? get owner;
|
||||
bool get isPrivate;
|
||||
bool get isTopLevel;
|
||||
List<InstanceMirror> get metadata;
|
||||
}
|
||||
|
||||
abstract class ObjectMirror implements Mirror {
|
||||
InstanceMirror invoke(Symbol memberName, List positionalArgs, [Map<Symbol, dynamic> namedArgs]);
|
||||
InstanceMirror getField(Symbol fieldName);
|
||||
InstanceMirror setField(Symbol fieldName, Object? value);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Type System
|
||||
Complete type reflection support:
|
||||
```dart
|
||||
abstract class TypeMirror implements DeclarationMirror {
|
||||
bool get hasReflectedType;
|
||||
Type get reflectedType;
|
||||
List<TypeVariableMirror> get typeVariables;
|
||||
List<TypeMirror> get typeArguments;
|
||||
bool get isOriginalDeclaration;
|
||||
TypeMirror get originalDeclaration;
|
||||
bool isSubtypeOf(TypeMirror other);
|
||||
bool isAssignableTo(TypeMirror other);
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### Phase-based Approach
|
||||
1. **Core Mirror System**
|
||||
- Mirror system implementation
|
||||
- Basic reflection capabilities
|
||||
- Type system foundation
|
||||
- Symbol handling
|
||||
|
||||
2. **Type System**
|
||||
- Complete type mirrors
|
||||
- Generic support
|
||||
- Type relationships
|
||||
- Type variables
|
||||
|
||||
3. **Library Support**
|
||||
- Library mirrors
|
||||
- Declaration handling
|
||||
- Privacy scope
|
||||
- Dependencies
|
||||
|
||||
4. **Platform Support**
|
||||
- Web optimization
|
||||
- Native platform support
|
||||
- Performance tuning
|
||||
- Memory optimization
|
||||
|
||||
### AI Integration
|
||||
- Interface validation
|
||||
- Test generation
|
||||
- Performance optimization
|
||||
- Code pattern verification
|
||||
|
||||
### Quality Assurance
|
||||
- Comprehensive test coverage
|
||||
- Performance benchmarking
|
||||
- Cross-platform validation
|
||||
- Memory usage optimization
|
||||
|
||||
## Cross-Platform Support
|
||||
|
||||
### Web Platform
|
||||
- Tree-shaking compatibility
|
||||
- Minification support
|
||||
- Browser optimizations
|
||||
- Memory efficiency
|
||||
|
||||
### Native Platforms
|
||||
- AOT compilation support
|
||||
- Platform-specific optimizations
|
||||
- Resource management
|
||||
- Performance tuning
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Sprint Cycle
|
||||
1. Interface Implementation
|
||||
2. Behavior Verification
|
||||
3. AI-Assisted Testing
|
||||
4. Performance Optimization
|
||||
5. Documentation Update
|
||||
|
||||
### AI-CDS Integration
|
||||
1. API compliance verification
|
||||
2. Test scenario generation
|
||||
3. Implementation validation
|
||||
4. Performance analysis
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### Functional Requirements
|
||||
- Complete mirrors API implementation
|
||||
- Cross-platform compatibility
|
||||
- Full type system support
|
||||
- Library handling
|
||||
|
||||
### Performance Targets
|
||||
- Fast reflection operations
|
||||
- Efficient memory usage
|
||||
- Quick startup time
|
||||
- Low runtime overhead
|
||||
|
||||
### Quality Metrics
|
||||
- 100% test coverage
|
||||
- API compliance
|
||||
- Performance benchmarks
|
||||
- Memory targets
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Immediate Actions
|
||||
1. Implement MirrorSystem
|
||||
2. Complete core mirrors
|
||||
3. Add type system support
|
||||
4. Begin library handling
|
||||
|
||||
### Long-term Goals
|
||||
1. Full API implementation
|
||||
2. Platform optimizations
|
||||
3. Performance tuning
|
||||
4. Documentation completion
|
||||
|
||||
## Support and Maintenance
|
||||
|
||||
### Ongoing Tasks
|
||||
- API compliance monitoring
|
||||
- Performance tracking
|
||||
- Cross-platform testing
|
||||
- Documentation updates
|
||||
|
||||
### Future Considerations
|
||||
- New platform support
|
||||
- Performance improvements
|
||||
- API enhancements
|
||||
- Optimization opportunities
|
||||
|
||||
This overview provides a comprehensive guide to our reflection system implementation, focusing on following the Dart mirrors API while ensuring cross-platform compatibility and performance.
|
|
@ -1,16 +1,20 @@
|
|||
# Dart Pure Reflection
|
||||
# Platform Reflection
|
||||
|
||||
A lightweight, cross-platform reflection system for Dart that provides runtime type introspection and manipulation without using `dart:mirrors` or code generation.
|
||||
A lightweight, cross-platform reflection system for Dart that provides runtime type introspection and manipulation with an API similar to `dart:mirrors` but without its limitations.
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ Works on all platforms (Web, Mobile, Desktop)
|
||||
- ✅ No dependency on `dart:mirrors`
|
||||
- ✅ No code generation required
|
||||
- ✅ Pure runtime reflection
|
||||
- ✅ No code generation required
|
||||
- ✅ No manual registration needed
|
||||
- ✅ Complete mirror-based API
|
||||
- ✅ Type-safe property access
|
||||
- ✅ Method invocation with argument validation
|
||||
- ✅ Constructor invocation support
|
||||
- ✅ Library and isolate reflection
|
||||
- ✅ Full MirrorSystem implementation
|
||||
- ✅ Comprehensive error handling
|
||||
|
||||
## Installation
|
||||
|
@ -19,91 +23,136 @@ Add this to your package's `pubspec.yaml` file:
|
|||
|
||||
```yaml
|
||||
dependencies:
|
||||
reflection: ^1.0.0
|
||||
platform_reflection: ^0.1.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Setup
|
||||
### Basic Reflection
|
||||
|
||||
1. Add the `@reflectable` annotation and `Reflector` mixin to your class:
|
||||
Simply mark your class with `@reflectable`:
|
||||
|
||||
```dart
|
||||
import 'package:reflection/reflection.dart';
|
||||
import 'package:platform_reflection/reflection.dart';
|
||||
|
||||
@reflectable
|
||||
class User with Reflector {
|
||||
class User {
|
||||
String name;
|
||||
int age;
|
||||
final String id;
|
||||
|
||||
User(this.name, this.age, {required this.id});
|
||||
|
||||
void birthday() {
|
||||
age++;
|
||||
}
|
||||
|
||||
String greet(String greeting) {
|
||||
return '$greeting, $name!';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Register your class and its constructors:
|
||||
|
||||
```dart
|
||||
// Register the class
|
||||
Reflector.register(User);
|
||||
|
||||
// Register constructors
|
||||
Reflector.registerConstructor(
|
||||
User,
|
||||
'', // Default constructor
|
||||
(String name, int age, {String? id}) {
|
||||
if (id == null) throw ArgumentError.notNull('id');
|
||||
return User(name, age, id: id);
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
### Reflecting on Types
|
||||
Then use reflection directly:
|
||||
|
||||
```dart
|
||||
// Get the reflector instance
|
||||
final reflector = RuntimeReflector.instance;
|
||||
|
||||
// Get type metadata
|
||||
final userType = reflector.reflectType(User);
|
||||
print('Type name: ${userType.name}');
|
||||
print('Properties: ${userType.properties.keys.join(', ')}');
|
||||
print('Methods: ${userType.methods.keys.join(', ')}');
|
||||
```
|
||||
// Create instance using reflection
|
||||
final user = reflector.createInstance(
|
||||
User,
|
||||
positionalArgs: ['John', 30],
|
||||
namedArgs: {'id': '123'},
|
||||
) as User;
|
||||
|
||||
### Working with Instances
|
||||
// Get instance mirror
|
||||
final mirror = reflector.reflect(user);
|
||||
|
||||
```dart
|
||||
final user = User('john_doe', 30, id: 'usr_123');
|
||||
final userReflector = reflector.reflect(user);
|
||||
// Access properties
|
||||
print(mirror.getField(const Symbol('name')).reflectee); // John
|
||||
print(mirror.getField(const Symbol('age')).reflectee); // 30
|
||||
|
||||
// Read properties
|
||||
final name = userReflector.getField('name'); // john_doe
|
||||
final age = userReflector.getField('age'); // 30
|
||||
|
||||
// Write properties
|
||||
userReflector.setField('name', 'jane_doe');
|
||||
userReflector.setField('age', 25);
|
||||
// Modify properties
|
||||
mirror.setField(const Symbol('name'), 'Jane');
|
||||
mirror.setField(const Symbol('age'), 25);
|
||||
|
||||
// Invoke methods
|
||||
userReflector.invoke('someMethod', ['arg1', 'arg2']);
|
||||
mirror.invoke(const Symbol('birthday'), []);
|
||||
final greeting = mirror.invoke(const Symbol('greet'), ['Hello']).reflectee;
|
||||
print(greeting); // Hello, Jane!
|
||||
```
|
||||
|
||||
### Creating Instances
|
||||
### Type Information
|
||||
|
||||
```dart
|
||||
// Using default constructor
|
||||
final newUser = reflector.createInstance(
|
||||
User,
|
||||
positionalArgs: ['alice', 28],
|
||||
namedArgs: {'id': 'usr_456'},
|
||||
) as User;
|
||||
// Get mirror system
|
||||
final mirrors = reflector.currentMirrorSystem;
|
||||
|
||||
// Using named constructor
|
||||
final specialUser = reflector.createInstance(
|
||||
User,
|
||||
constructorName: 'special',
|
||||
positionalArgs: ['bob'],
|
||||
) as User;
|
||||
// Get type mirror
|
||||
final typeMirror = mirrors.reflectType(User);
|
||||
|
||||
// Access type information
|
||||
print(typeMirror.name); // User
|
||||
print(typeMirror.properties); // {name: PropertyMetadata(...), age: PropertyMetadata(...)}
|
||||
print(typeMirror.methods); // {birthday: MethodMetadata(...), greet: MethodMetadata(...)}
|
||||
|
||||
// Check type relationships
|
||||
if (typeMirror.isSubtypeOf(otherType)) {
|
||||
print('User is a subtype');
|
||||
}
|
||||
|
||||
// Get declarations
|
||||
final declarations = typeMirror.declarations;
|
||||
for (var member in declarations.values) {
|
||||
if (member is MethodMirror) {
|
||||
print('Method: ${member.simpleName}');
|
||||
} else if (member is VariableMirror) {
|
||||
print('Variable: ${member.simpleName}');
|
||||
}
|
||||
}
|
||||
|
||||
// Access special types
|
||||
print(mirrors.dynamicType.name); // dynamic
|
||||
print(mirrors.voidType.name); // void
|
||||
print(mirrors.neverType.name); // Never
|
||||
```
|
||||
|
||||
### Library Reflection
|
||||
|
||||
```dart
|
||||
// Get a library
|
||||
final library = mirrors.findLibrary(const Symbol('package:myapp/src/models.dart'));
|
||||
|
||||
// Access library members
|
||||
final declarations = library.declarations;
|
||||
for (var decl in declarations.values) {
|
||||
print('Declaration: ${decl.simpleName}');
|
||||
}
|
||||
|
||||
// Check imports
|
||||
for (var dep in library.libraryDependencies) {
|
||||
if (dep.isImport) {
|
||||
print('Imports: ${dep.targetLibrary?.uri}');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Isolate Reflection
|
||||
|
||||
```dart
|
||||
// Get current isolate
|
||||
final currentIsolate = mirrors.isolate;
|
||||
print('Current isolate: ${currentIsolate.debugName}');
|
||||
|
||||
// Reflect on another isolate
|
||||
final isolate = await Isolate.spawn(workerFunction, message);
|
||||
final isolateMirror = reflector.reflectIsolate(isolate, 'worker');
|
||||
|
||||
// Control isolate
|
||||
await isolateMirror.pause();
|
||||
await isolateMirror.resume();
|
||||
await isolateMirror.kill();
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
@ -117,46 +166,23 @@ The package provides specific exceptions for different error cases:
|
|||
|
||||
```dart
|
||||
try {
|
||||
reflector.reflect(NonReflectableClass());
|
||||
reflect(NonReflectableClass());
|
||||
} catch (e) {
|
||||
print(e); // NotReflectableException: Type "NonReflectableClass" is not marked as @reflectable
|
||||
print(e); // NotReflectableException: Type NonReflectableClass is not reflectable
|
||||
}
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
See the [example](example/reflection_example.dart) for a complete working demonstration.
|
||||
|
||||
## Limitations
|
||||
|
||||
1. Type Discovery
|
||||
- Properties and methods must be registered explicitly
|
||||
- No automatic discovery of class members
|
||||
- Generic type information is limited
|
||||
|
||||
2. Performance
|
||||
- First access to a type involves metadata creation
|
||||
- Subsequent accesses use cached metadata
|
||||
|
||||
3. Private Members
|
||||
- Private fields and methods cannot be accessed
|
||||
- Reflection is limited to public API
|
||||
|
||||
## Design Philosophy
|
||||
|
||||
This package is inspired by:
|
||||
This package provides a reflection API that closely mirrors the design of `dart:mirrors` while being:
|
||||
|
||||
- **dart:mirrors**: API design and metadata structure
|
||||
- **fake_reflection**: Registration-based approach
|
||||
- **mirrors.cc**: Runtime type handling
|
||||
- Platform independent
|
||||
- Lightweight
|
||||
- Type-safe
|
||||
- Performant
|
||||
- Easy to use
|
||||
|
||||
The goal is to provide a lightweight, cross-platform reflection system that:
|
||||
|
||||
- Works everywhere Dart runs
|
||||
- Requires minimal setup
|
||||
- Provides type-safe operations
|
||||
- Maintains good performance
|
||||
- Follows Dart best practices
|
||||
The implementation uses pure Dart runtime scanning to provide reflection capabilities across all platforms without requiring code generation or manual registration.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
@ -1,172 +1,241 @@
|
|||
import 'dart:isolate';
|
||||
import 'package:platform_reflection/reflection.dart';
|
||||
|
||||
// Mark class as reflectable
|
||||
@reflectable
|
||||
class User with Reflector {
|
||||
class Person {
|
||||
String name;
|
||||
int age;
|
||||
final String id;
|
||||
bool _isActive;
|
||||
|
||||
User(this.name, this.age, {required this.id, bool isActive = true})
|
||||
: _isActive = isActive;
|
||||
|
||||
// Guest constructor
|
||||
User.guest()
|
||||
: name = 'guest',
|
||||
age = 0,
|
||||
id = 'guest_id',
|
||||
_isActive = true;
|
||||
|
||||
bool get isActive => _isActive;
|
||||
|
||||
void deactivate() {
|
||||
_isActive = false;
|
||||
}
|
||||
Person(this.name, this.age, {required this.id});
|
||||
|
||||
void birthday() {
|
||||
age++;
|
||||
}
|
||||
|
||||
String greet([String greeting = 'Hello']) => '$greeting, $name!';
|
||||
String greet(String greeting) {
|
||||
return '$greeting, $name!';
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'User(name: $name age: $age id: $id isActive: $isActive)';
|
||||
static Person create(String name, int age, String id) {
|
||||
return Person(name, age, id: id);
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
// Register User class for reflection
|
||||
Reflector.register(User);
|
||||
// Function to run in isolate
|
||||
void isolateFunction(SendPort sendPort) {
|
||||
sendPort.send('Hello from isolate!');
|
||||
}
|
||||
|
||||
void main() async {
|
||||
// Register Person class for reflection
|
||||
Reflector.registerType(Person);
|
||||
|
||||
// Register properties
|
||||
Reflector.registerProperty(User, 'name', String);
|
||||
Reflector.registerProperty(User, 'age', int);
|
||||
Reflector.registerProperty(User, 'id', String, isWritable: false);
|
||||
Reflector.registerProperty(User, 'isActive', bool, isWritable: false);
|
||||
Reflector.registerPropertyMetadata(
|
||||
Person,
|
||||
'name',
|
||||
PropertyMetadata(
|
||||
name: 'name',
|
||||
type: String,
|
||||
isReadable: true,
|
||||
isWritable: true,
|
||||
),
|
||||
);
|
||||
|
||||
Reflector.registerPropertyMetadata(
|
||||
Person,
|
||||
'age',
|
||||
PropertyMetadata(
|
||||
name: 'age',
|
||||
type: int,
|
||||
isReadable: true,
|
||||
isWritable: true,
|
||||
),
|
||||
);
|
||||
|
||||
Reflector.registerPropertyMetadata(
|
||||
Person,
|
||||
'id',
|
||||
PropertyMetadata(
|
||||
name: 'id',
|
||||
type: String,
|
||||
isReadable: true,
|
||||
isWritable: false,
|
||||
),
|
||||
);
|
||||
|
||||
// Register methods
|
||||
Reflector.registerMethod(
|
||||
User,
|
||||
Reflector.registerMethodMetadata(
|
||||
Person,
|
||||
'birthday',
|
||||
[],
|
||||
true, // returns void
|
||||
MethodMetadata(
|
||||
name: 'birthday',
|
||||
parameterTypes: [],
|
||||
parameters: [],
|
||||
returnsVoid: true,
|
||||
),
|
||||
);
|
||||
Reflector.registerMethod(
|
||||
User,
|
||||
|
||||
Reflector.registerMethodMetadata(
|
||||
Person,
|
||||
'greet',
|
||||
[String],
|
||||
false, // returns String
|
||||
parameterNames: ['greeting'],
|
||||
isRequired: [false], // optional parameter
|
||||
);
|
||||
Reflector.registerMethod(
|
||||
User,
|
||||
'deactivate',
|
||||
[],
|
||||
true, // returns void
|
||||
MethodMetadata(
|
||||
name: 'greet',
|
||||
parameterTypes: [String],
|
||||
parameters: [
|
||||
ParameterMetadata(
|
||||
name: 'greeting',
|
||||
type: String,
|
||||
isRequired: true,
|
||||
),
|
||||
],
|
||||
returnsVoid: false,
|
||||
),
|
||||
);
|
||||
|
||||
// Register constructors
|
||||
Reflector.registerConstructor(
|
||||
User,
|
||||
'', // default constructor
|
||||
(String name, int age, {required String id, bool isActive = true}) =>
|
||||
User(name, age, id: id, isActive: isActive),
|
||||
parameterTypes: [String, int, String, bool],
|
||||
parameterNames: ['name', 'age', 'id', 'isActive'],
|
||||
isRequired: [true, true, true, false],
|
||||
isNamed: [false, false, true, true],
|
||||
// Register constructor
|
||||
Reflector.registerConstructorMetadata(
|
||||
Person,
|
||||
ConstructorMetadata(
|
||||
name: '',
|
||||
parameterTypes: [String, int, String],
|
||||
parameters: [
|
||||
ParameterMetadata(name: 'name', type: String, isRequired: true),
|
||||
ParameterMetadata(name: 'age', type: int, isRequired: true),
|
||||
ParameterMetadata(
|
||||
name: 'id', type: String, isRequired: true, isNamed: true),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Reflector.registerConstructor(
|
||||
User,
|
||||
'guest',
|
||||
() => User.guest(),
|
||||
Reflector.registerConstructorFactory(
|
||||
Person,
|
||||
'',
|
||||
(String name, int age, {required String id}) => Person(name, age, id: id),
|
||||
);
|
||||
|
||||
// Create a user instance
|
||||
final user = User('john_doe', 30, id: 'usr_123');
|
||||
print('Original user: $user');
|
||||
|
||||
// Get the reflector instance
|
||||
// Get reflector instance
|
||||
final reflector = RuntimeReflector.instance;
|
||||
|
||||
// Reflect on the User type
|
||||
final userType = reflector.reflectType(User);
|
||||
// Get mirror system
|
||||
final mirrorSystem = reflector.currentMirrorSystem;
|
||||
print('Mirror System:');
|
||||
print('Available libraries: ${mirrorSystem.libraries.keys.join(', ')}');
|
||||
print('Dynamic type: ${mirrorSystem.dynamicType.name}');
|
||||
print('Void type: ${mirrorSystem.voidType.name}');
|
||||
print('Never type: ${mirrorSystem.neverType.name}');
|
||||
|
||||
// Create instance using reflection
|
||||
final person = reflector.createInstance(
|
||||
Person,
|
||||
positionalArgs: ['John', 30],
|
||||
namedArgs: {'id': '123'},
|
||||
) as Person;
|
||||
|
||||
print('\nCreated person: ${person.name}, age ${person.age}, id ${person.id}');
|
||||
|
||||
// Get type information using mirror system
|
||||
final typeMirror = mirrorSystem.reflectType(Person);
|
||||
print('\nType information:');
|
||||
print('Type name: ${userType.name}');
|
||||
print('Properties: ${userType.properties.keys.join(', ')}');
|
||||
print('Methods: ${userType.methods.keys.join(', ')}');
|
||||
print('Constructors: ${userType.constructors.map((c) => c.name).join(', ')}');
|
||||
print('Name: ${typeMirror.name}');
|
||||
print('Properties: ${typeMirror.properties.keys}');
|
||||
print('Methods: ${typeMirror.methods.keys}');
|
||||
|
||||
// Create an instance reflector
|
||||
final userReflector = reflector.reflect(user);
|
||||
// Get instance mirror
|
||||
final instanceMirror = reflector.reflect(person);
|
||||
|
||||
// Read properties
|
||||
print('\nReading properties:');
|
||||
print('Name: ${userReflector.getField('name')}');
|
||||
print('Age: ${userReflector.getField('age')}');
|
||||
print('ID: ${userReflector.getField('id')}');
|
||||
print('Is active: ${userReflector.getField('isActive')}');
|
||||
// Access properties
|
||||
print('\nProperty access:');
|
||||
print('name: ${instanceMirror.getField(const Symbol('name')).reflectee}');
|
||||
print('age: ${instanceMirror.getField(const Symbol('age')).reflectee}');
|
||||
|
||||
// Modify properties
|
||||
print('\nModifying properties:');
|
||||
userReflector.setField('name', 'jane_doe');
|
||||
userReflector.setField('age', 25);
|
||||
print('Modified user: $user');
|
||||
instanceMirror.setField(const Symbol('name'), 'Jane');
|
||||
instanceMirror.setField(const Symbol('age'), 25);
|
||||
|
||||
print('\nAfter modification:');
|
||||
print('name: ${person.name}');
|
||||
print('age: ${person.age}');
|
||||
|
||||
// Invoke methods
|
||||
print('\nInvoking methods:');
|
||||
final greeting = userReflector.invoke('greet', ['Hi']);
|
||||
print('\nMethod invocation:');
|
||||
final greeting =
|
||||
instanceMirror.invoke(const Symbol('greet'), ['Hello']).reflectee;
|
||||
print('Greeting: $greeting');
|
||||
|
||||
userReflector.invoke('birthday', []);
|
||||
print('After birthday: $user');
|
||||
instanceMirror.invoke(const Symbol('birthday'), []);
|
||||
print('After birthday: age ${person.age}');
|
||||
|
||||
userReflector.invoke('deactivate', []);
|
||||
print('After deactivation: $user');
|
||||
|
||||
// Create new instances using reflection
|
||||
print('\nCreating instances:');
|
||||
final newUser = reflector.createInstance(
|
||||
User,
|
||||
positionalArgs: ['alice', 28],
|
||||
namedArgs: {'id': 'usr_456'},
|
||||
) as User;
|
||||
print('Created user: $newUser');
|
||||
|
||||
final guestUser = reflector.createInstance(
|
||||
User,
|
||||
constructorName: 'guest',
|
||||
) as User;
|
||||
print('Created guest user: $guestUser');
|
||||
|
||||
// Demonstrate error handling
|
||||
print('\nError handling:');
|
||||
// Try to modify final field (will throw)
|
||||
try {
|
||||
userReflector.setField('id', 'new_id'); // Should throw - id is final
|
||||
instanceMirror.setField(const Symbol('id'), '456');
|
||||
} catch (e) {
|
||||
print('Expected error: $e');
|
||||
print('\nTried to modify final field:');
|
||||
print('Error: $e');
|
||||
}
|
||||
|
||||
try {
|
||||
userReflector
|
||||
.invoke('unknownMethod', []); // Should throw - method doesn't exist
|
||||
} catch (e) {
|
||||
print('Expected error: $e');
|
||||
}
|
||||
// Library reflection using mirror system
|
||||
print('\nLibrary reflection:');
|
||||
final libraryMirror = mirrorSystem.findLibrary(const Symbol('dart:core'));
|
||||
print('Library name: ${libraryMirror.qualifiedName}');
|
||||
print('Library URI: ${libraryMirror.uri}');
|
||||
print('Top-level declarations: ${libraryMirror.declarations.keys}');
|
||||
|
||||
// Demonstrate non-reflectable class
|
||||
print('\nNon-reflectable class:');
|
||||
try {
|
||||
final nonReflectable = NonReflectable();
|
||||
reflector.reflect(nonReflectable);
|
||||
} catch (e) {
|
||||
print('Expected error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Class without @reflectable annotation for testing
|
||||
class NonReflectable {
|
||||
String value = 'test';
|
||||
// Check type relationships
|
||||
print('\nType relationships:');
|
||||
final stringType = mirrorSystem.reflectType(String);
|
||||
final dynamicType = mirrorSystem.dynamicType;
|
||||
print(
|
||||
'String assignable to dynamic: ${stringType.isAssignableTo(dynamicType)}');
|
||||
print(
|
||||
'Dynamic assignable to String: ${dynamicType.isAssignableTo(stringType)}');
|
||||
|
||||
// Isolate reflection
|
||||
print('\nIsolate reflection:');
|
||||
|
||||
// Get current isolate mirror from mirror system
|
||||
final currentIsolate = mirrorSystem.isolate;
|
||||
print(
|
||||
'Current isolate: ${currentIsolate.debugName} (isCurrent: ${currentIsolate.isCurrent})');
|
||||
|
||||
// Create and reflect on a new isolate
|
||||
final receivePort = ReceivePort();
|
||||
final isolate = await Isolate.spawn(
|
||||
isolateFunction,
|
||||
receivePort.sendPort,
|
||||
);
|
||||
|
||||
final isolateMirror =
|
||||
reflector.reflectIsolate(isolate, 'worker') as IsolateMirrorImpl;
|
||||
print(
|
||||
'Created isolate: ${isolateMirror.debugName} (isCurrent: ${isolateMirror.isCurrent})');
|
||||
|
||||
// Add error and exit listeners
|
||||
isolateMirror.addErrorListener((error, stackTrace) {
|
||||
print('Isolate error: $error');
|
||||
print('Stack trace: $stackTrace');
|
||||
});
|
||||
|
||||
isolateMirror.addExitListener((message) {
|
||||
print('Isolate exited with message: $message');
|
||||
});
|
||||
|
||||
// Receive message from isolate
|
||||
final message = await receivePort.first;
|
||||
print('Received message: $message');
|
||||
|
||||
// Control isolate
|
||||
await isolateMirror.pause();
|
||||
print('Isolate paused');
|
||||
|
||||
await isolateMirror.resume();
|
||||
print('Isolate resumed');
|
||||
|
||||
await isolateMirror.kill();
|
||||
print('Isolate killed');
|
||||
|
||||
// Clean up
|
||||
receivePort.close();
|
||||
}
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
/// A lightweight cross-platform reflection system for Dart.
|
||||
/// A lightweight, cross-platform reflection system for Dart.
|
||||
library reflection;
|
||||
|
||||
export 'src/reflector.dart';
|
||||
// Core functionality
|
||||
export 'src/core/reflector.dart';
|
||||
export 'src/core/scanner.dart';
|
||||
export 'src/core/runtime_reflector.dart';
|
||||
|
||||
// Mirror API
|
||||
export 'src/mirrors.dart';
|
||||
export 'src/mirrors/isolate_mirror_impl.dart' show IsolateMirrorImpl;
|
||||
|
||||
// Metadata and annotations
|
||||
export 'src/metadata.dart';
|
||||
export 'src/annotations.dart';
|
||||
export 'src/annotations.dart' show reflectable;
|
||||
|
||||
// Exceptions
|
||||
export 'src/exceptions.dart';
|
||||
export 'src/types.dart';
|
||||
|
|
|
@ -122,95 +122,3 @@ class Reflectable {
|
|||
|
||||
/// The annotation used to mark classes as reflectable.
|
||||
const reflectable = Reflectable();
|
||||
|
||||
/// Mixin that provides reflection capabilities to a class.
|
||||
mixin Reflector {
|
||||
/// Register this type for reflection.
|
||||
/// This should be called in the class's static initializer.
|
||||
static void register(Type type) {
|
||||
if (!ReflectionRegistry.isRegistered(type)) {
|
||||
ReflectionRegistry.registerType(type);
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a property for reflection.
|
||||
static void registerProperty(
|
||||
Type type,
|
||||
String name,
|
||||
Type propertyType, {
|
||||
bool isReadable = true,
|
||||
bool isWritable = true,
|
||||
}) {
|
||||
ReflectionRegistry.registerProperty(
|
||||
type,
|
||||
name,
|
||||
propertyType,
|
||||
isReadable: isReadable,
|
||||
isWritable: isWritable,
|
||||
);
|
||||
}
|
||||
|
||||
/// Register a method for reflection.
|
||||
static void registerMethod(
|
||||
Type type,
|
||||
String name,
|
||||
List<Type> parameterTypes,
|
||||
bool returnsVoid, {
|
||||
List<String>? parameterNames,
|
||||
List<bool>? isRequired,
|
||||
List<bool>? isNamed,
|
||||
}) {
|
||||
ReflectionRegistry.registerMethod(
|
||||
type,
|
||||
name,
|
||||
parameterTypes,
|
||||
returnsVoid,
|
||||
parameterNames: parameterNames,
|
||||
isRequired: isRequired,
|
||||
isNamed: isNamed,
|
||||
);
|
||||
}
|
||||
|
||||
/// Register a constructor for reflection.
|
||||
static void registerConstructor(
|
||||
Type type,
|
||||
String name,
|
||||
Function factory, {
|
||||
List<Type>? parameterTypes,
|
||||
List<String>? parameterNames,
|
||||
List<bool>? isRequired,
|
||||
List<bool>? isNamed,
|
||||
}) {
|
||||
ReflectionRegistry.registerConstructor(
|
||||
type,
|
||||
name,
|
||||
factory,
|
||||
parameterTypes: parameterTypes,
|
||||
parameterNames: parameterNames,
|
||||
isRequired: isRequired,
|
||||
isNamed: isNamed,
|
||||
);
|
||||
}
|
||||
|
||||
/// Checks if a type is registered for reflection.
|
||||
static bool isReflectable(Type type) => ReflectionRegistry.isRegistered(type);
|
||||
|
||||
/// Gets property metadata for a type.
|
||||
static Map<String, PropertyMetadata>? getPropertyMetadata(Type type) =>
|
||||
ReflectionRegistry.getProperties(type);
|
||||
|
||||
/// Gets method metadata for a type.
|
||||
static Map<String, MethodMetadata>? getMethodMetadata(Type type) =>
|
||||
ReflectionRegistry.getMethods(type);
|
||||
|
||||
/// Gets constructor metadata for a type.
|
||||
static List<ConstructorMetadata>? getConstructorMetadata(Type type) =>
|
||||
ReflectionRegistry.getConstructors(type);
|
||||
|
||||
/// Gets a constructor factory for a type.
|
||||
static Function? getConstructor(Type type, String name) =>
|
||||
ReflectionRegistry.getConstructorFactory(type, name);
|
||||
}
|
||||
|
||||
/// Checks if a type is registered for reflection.
|
||||
bool isReflectable(Type type) => Reflector.isReflectable(type);
|
||||
|
|
197
packages/reflection/lib/src/core/reflector.dart
Normal file
197
packages/reflection/lib/src/core/reflector.dart
Normal file
|
@ -0,0 +1,197 @@
|
|||
import 'dart:collection';
|
||||
import '../metadata.dart';
|
||||
import '../mirrors.dart';
|
||||
import '../mirrors/mirrors.dart';
|
||||
|
||||
/// Static registry for reflection metadata.
|
||||
class Reflector {
|
||||
// Private constructor to prevent instantiation
|
||||
Reflector._();
|
||||
|
||||
// Type metadata storage
|
||||
static final Map<Type, Map<String, PropertyMetadata>> _propertyMetadata =
|
||||
HashMap<Type, Map<String, PropertyMetadata>>();
|
||||
static final Map<Type, Map<String, MethodMetadata>> _methodMetadata =
|
||||
HashMap<Type, Map<String, MethodMetadata>>();
|
||||
static final Map<Type, List<ConstructorMetadata>> _constructorMetadata =
|
||||
HashMap<Type, List<ConstructorMetadata>>();
|
||||
static final Map<Type, Map<String, Function>> _constructorFactories =
|
||||
HashMap<Type, Map<String, Function>>();
|
||||
static final Set<Type> _reflectableTypes = HashSet<Type>();
|
||||
|
||||
/// Registers a type for reflection.
|
||||
static void registerType(Type type) {
|
||||
_reflectableTypes.add(type);
|
||||
_propertyMetadata.putIfAbsent(
|
||||
type, () => HashMap<String, PropertyMetadata>());
|
||||
_methodMetadata.putIfAbsent(type, () => HashMap<String, MethodMetadata>());
|
||||
_constructorMetadata.putIfAbsent(type, () => []);
|
||||
_constructorFactories.putIfAbsent(type, () => {});
|
||||
}
|
||||
|
||||
/// Register this type for reflection.
|
||||
static void register(Type type) {
|
||||
if (!isReflectable(type)) {
|
||||
registerType(type);
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a property for reflection.
|
||||
static void registerProperty(
|
||||
Type type,
|
||||
String name,
|
||||
Type propertyType, {
|
||||
bool isReadable = true,
|
||||
bool isWritable = true,
|
||||
}) {
|
||||
registerPropertyMetadata(
|
||||
type,
|
||||
name,
|
||||
PropertyMetadata(
|
||||
name: name,
|
||||
type: propertyType,
|
||||
isReadable: isReadable,
|
||||
isWritable: isWritable,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Register a method for reflection.
|
||||
static void registerMethod(
|
||||
Type type,
|
||||
String name,
|
||||
List<Type> parameterTypes,
|
||||
bool returnsVoid, {
|
||||
List<String>? parameterNames,
|
||||
List<bool>? isRequired,
|
||||
List<bool>? isNamed,
|
||||
bool isStatic = false,
|
||||
}) {
|
||||
final parameters = <ParameterMetadata>[];
|
||||
for (var i = 0; i < parameterTypes.length; i++) {
|
||||
parameters.add(ParameterMetadata(
|
||||
name: parameterNames?[i] ?? 'param$i',
|
||||
type: parameterTypes[i],
|
||||
isRequired: isRequired?[i] ?? true,
|
||||
isNamed: isNamed?[i] ?? false,
|
||||
));
|
||||
}
|
||||
|
||||
registerMethodMetadata(
|
||||
type,
|
||||
name,
|
||||
MethodMetadata(
|
||||
name: name,
|
||||
parameterTypes: parameterTypes,
|
||||
parameters: parameters,
|
||||
returnsVoid: returnsVoid,
|
||||
isStatic: isStatic,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Register a constructor for reflection.
|
||||
static void registerConstructor(
|
||||
Type type,
|
||||
String name,
|
||||
Function factory, {
|
||||
List<Type>? parameterTypes,
|
||||
List<String>? parameterNames,
|
||||
List<bool>? isRequired,
|
||||
List<bool>? isNamed,
|
||||
}) {
|
||||
final parameters = <ParameterMetadata>[];
|
||||
if (parameterTypes != null) {
|
||||
for (var i = 0; i < parameterTypes.length; i++) {
|
||||
parameters.add(ParameterMetadata(
|
||||
name: parameterNames?[i] ?? 'param$i',
|
||||
type: parameterTypes[i],
|
||||
isRequired: isRequired?[i] ?? true,
|
||||
isNamed: isNamed?[i] ?? false,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
registerConstructorMetadata(
|
||||
type,
|
||||
ConstructorMetadata(
|
||||
name: name,
|
||||
parameterTypes: parameterTypes ?? [],
|
||||
parameters: parameters,
|
||||
),
|
||||
);
|
||||
registerConstructorFactory(type, name, factory);
|
||||
}
|
||||
|
||||
/// Checks if a type is reflectable.
|
||||
static bool isReflectable(Type type) {
|
||||
return _reflectableTypes.contains(type);
|
||||
}
|
||||
|
||||
/// Gets property metadata for a type.
|
||||
static Map<String, PropertyMetadata>? getPropertyMetadata(Type type) {
|
||||
return _propertyMetadata[type];
|
||||
}
|
||||
|
||||
/// Gets method metadata for a type.
|
||||
static Map<String, MethodMetadata>? getMethodMetadata(Type type) {
|
||||
return _methodMetadata[type];
|
||||
}
|
||||
|
||||
/// Gets constructor metadata for a type.
|
||||
static List<ConstructorMetadata>? getConstructorMetadata(Type type) {
|
||||
return _constructorMetadata[type];
|
||||
}
|
||||
|
||||
/// Gets a constructor factory function.
|
||||
static Function? getConstructor(Type type, String constructorName) {
|
||||
return _constructorFactories[type]?[constructorName];
|
||||
}
|
||||
|
||||
/// Registers property metadata for a type.
|
||||
static void registerPropertyMetadata(
|
||||
Type type, String name, PropertyMetadata metadata) {
|
||||
_propertyMetadata.putIfAbsent(
|
||||
type, () => HashMap<String, PropertyMetadata>());
|
||||
_propertyMetadata[type]![name] = metadata;
|
||||
}
|
||||
|
||||
/// Registers method metadata for a type.
|
||||
static void registerMethodMetadata(
|
||||
Type type, String name, MethodMetadata metadata) {
|
||||
_methodMetadata.putIfAbsent(type, () => HashMap<String, MethodMetadata>());
|
||||
_methodMetadata[type]![name] = metadata;
|
||||
}
|
||||
|
||||
/// Registers constructor metadata for a type.
|
||||
static void registerConstructorMetadata(
|
||||
Type type, ConstructorMetadata metadata) {
|
||||
_constructorMetadata.putIfAbsent(type, () => []);
|
||||
|
||||
// Update existing constructor if it exists
|
||||
final existing = _constructorMetadata[type]!
|
||||
.indexWhere((ctor) => ctor.name == metadata.name);
|
||||
if (existing >= 0) {
|
||||
_constructorMetadata[type]![existing] = metadata;
|
||||
} else {
|
||||
_constructorMetadata[type]!.add(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a constructor factory function.
|
||||
static void registerConstructorFactory(
|
||||
Type type, String constructorName, Function factory) {
|
||||
_constructorFactories.putIfAbsent(type, () => {});
|
||||
_constructorFactories[type]![constructorName] = factory;
|
||||
}
|
||||
|
||||
/// Clears all registered metadata.
|
||||
/// This is primarily used for testing.
|
||||
static void reset() {
|
||||
_propertyMetadata.clear();
|
||||
_methodMetadata.clear();
|
||||
_constructorMetadata.clear();
|
||||
_constructorFactories.clear();
|
||||
_reflectableTypes.clear();
|
||||
}
|
||||
}
|
307
packages/reflection/lib/src/core/runtime_reflector.dart
Normal file
307
packages/reflection/lib/src/core/runtime_reflector.dart
Normal file
|
@ -0,0 +1,307 @@
|
|||
import 'package:meta/meta.dart';
|
||||
import 'dart:isolate' as isolate;
|
||||
import '../exceptions.dart';
|
||||
import '../metadata.dart';
|
||||
import '../mirrors.dart';
|
||||
import 'reflector.dart';
|
||||
import '../mirrors/base_mirror.dart';
|
||||
import '../mirrors/class_mirror_impl.dart';
|
||||
import '../mirrors/instance_mirror_impl.dart';
|
||||
import '../mirrors/method_mirror_impl.dart';
|
||||
import '../mirrors/parameter_mirror_impl.dart';
|
||||
import '../mirrors/type_mirror_impl.dart';
|
||||
import '../mirrors/variable_mirror_impl.dart';
|
||||
import '../mirrors/library_mirror_impl.dart';
|
||||
import '../mirrors/library_dependency_mirror_impl.dart';
|
||||
import '../mirrors/isolate_mirror_impl.dart';
|
||||
import '../mirrors/mirror_system_impl.dart';
|
||||
import '../mirrors/special_types.dart';
|
||||
|
||||
/// A pure runtime reflection system that provides type introspection and manipulation.
|
||||
class RuntimeReflector {
|
||||
/// The singleton instance of the reflector.
|
||||
static final instance = RuntimeReflector._();
|
||||
|
||||
/// The current mirror system.
|
||||
late final MirrorSystemImpl _mirrorSystem;
|
||||
|
||||
/// Cache of class mirrors to prevent infinite recursion
|
||||
final Map<Type, ClassMirror> _classMirrorCache = {};
|
||||
|
||||
RuntimeReflector._() {
|
||||
// Initialize mirror system
|
||||
_mirrorSystem = MirrorSystemImpl.current();
|
||||
}
|
||||
|
||||
/// Creates a new instance of a type using reflection.
|
||||
Object createInstance(
|
||||
Type type, {
|
||||
String constructorName = '',
|
||||
List<Object?> positionalArgs = const [],
|
||||
Map<String, Object?> namedArgs = const {},
|
||||
}) {
|
||||
// Check if type is reflectable
|
||||
if (!Reflector.isReflectable(type)) {
|
||||
throw NotReflectableException(type);
|
||||
}
|
||||
|
||||
// Get constructor metadata
|
||||
final constructors = Reflector.getConstructorMetadata(type);
|
||||
if (constructors == null || constructors.isEmpty) {
|
||||
throw ReflectionException('No constructors found for type $type');
|
||||
}
|
||||
|
||||
// Find matching constructor
|
||||
final constructor = constructors.firstWhere(
|
||||
(c) => c.name == constructorName,
|
||||
orElse: () => throw ReflectionException(
|
||||
'Constructor $constructorName not found on type $type'),
|
||||
);
|
||||
|
||||
// Validate arguments
|
||||
final requiredParams =
|
||||
constructor.parameters.where((p) => p.isRequired && !p.isNamed).length;
|
||||
if (positionalArgs.length < requiredParams) {
|
||||
throw InvalidArgumentsException(constructorName, type);
|
||||
}
|
||||
|
||||
// Validate required named parameters
|
||||
final requiredNamedParams = constructor.parameters
|
||||
.where((p) => p.isRequired && p.isNamed)
|
||||
.map((p) => p.name)
|
||||
.toSet();
|
||||
if (!requiredNamedParams.every(namedArgs.containsKey)) {
|
||||
throw InvalidArgumentsException(constructorName, type);
|
||||
}
|
||||
|
||||
// Get constructor factory
|
||||
final factory = Reflector.getConstructor(type, constructorName);
|
||||
if (factory == null) {
|
||||
throw ReflectionException(
|
||||
'No factory found for constructor $constructorName');
|
||||
}
|
||||
|
||||
// Create instance
|
||||
try {
|
||||
if (constructor.parameters.any((p) => p.isNamed)) {
|
||||
// For constructors with named parameters
|
||||
return Function.apply(
|
||||
factory,
|
||||
[],
|
||||
namedArgs.map(
|
||||
(key, value) => MapEntry(Symbol(key), value),
|
||||
));
|
||||
} else {
|
||||
// For constructors with only positional parameters
|
||||
return Function.apply(factory, positionalArgs);
|
||||
}
|
||||
} catch (e) {
|
||||
throw ReflectionException('Failed to create instance: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a TypeMirror for a given type.
|
||||
TypeMirror _createTypeMirror(Type type, String name, [ClassMirror? owner]) {
|
||||
if (type == voidType) {
|
||||
return TypeMirrorImpl.voidType(owner);
|
||||
}
|
||||
if (type == dynamicType) {
|
||||
return TypeMirrorImpl.dynamicType(owner);
|
||||
}
|
||||
return TypeMirrorImpl(
|
||||
type: type,
|
||||
name: name,
|
||||
owner: owner,
|
||||
metadata: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// Reflects on a type, returning its class mirror.
|
||||
ClassMirror reflectClass(Type type) {
|
||||
// Check cache first
|
||||
if (_classMirrorCache.containsKey(type)) {
|
||||
return _classMirrorCache[type]!;
|
||||
}
|
||||
|
||||
// Check if type is reflectable
|
||||
if (!Reflector.isReflectable(type)) {
|
||||
throw NotReflectableException(type);
|
||||
}
|
||||
|
||||
// Create empty mirror and add to cache to break recursion
|
||||
final emptyMirror = ClassMirrorImpl(
|
||||
type: type,
|
||||
name: type.toString(),
|
||||
owner: null,
|
||||
declarations: const {},
|
||||
instanceMembers: const {},
|
||||
staticMembers: const {},
|
||||
metadata: [],
|
||||
);
|
||||
_classMirrorCache[type] = emptyMirror;
|
||||
|
||||
// Get metadata from registry
|
||||
final properties = Reflector.getPropertyMetadata(type) ?? {};
|
||||
final methods = Reflector.getMethodMetadata(type) ?? {};
|
||||
final constructors = Reflector.getConstructorMetadata(type) ?? [];
|
||||
|
||||
// Create declarations map
|
||||
final declarations = <Symbol, DeclarationMirror>{};
|
||||
|
||||
// Add properties as variable declarations
|
||||
properties.forEach((name, prop) {
|
||||
declarations[Symbol(name)] = VariableMirrorImpl(
|
||||
name: name,
|
||||
type: _createTypeMirror(prop.type, prop.type.toString(), emptyMirror),
|
||||
owner: emptyMirror,
|
||||
isStatic: false,
|
||||
isFinal: !prop.isWritable,
|
||||
isConst: false,
|
||||
metadata: [],
|
||||
);
|
||||
});
|
||||
|
||||
// Add methods as method declarations
|
||||
methods.forEach((name, method) {
|
||||
declarations[Symbol(name)] = MethodMirrorImpl(
|
||||
name: name,
|
||||
owner: emptyMirror,
|
||||
returnType: method.returnsVoid
|
||||
? TypeMirrorImpl.voidType(emptyMirror)
|
||||
: TypeMirrorImpl.dynamicType(emptyMirror),
|
||||
parameters: method.parameters
|
||||
.map((param) => ParameterMirrorImpl(
|
||||
name: param.name,
|
||||
type: _createTypeMirror(
|
||||
param.type, param.type.toString(), emptyMirror),
|
||||
owner: emptyMirror,
|
||||
isOptional: !param.isRequired,
|
||||
isNamed: param.isNamed,
|
||||
metadata: [],
|
||||
))
|
||||
.toList(),
|
||||
isStatic: method.isStatic,
|
||||
metadata: [],
|
||||
);
|
||||
});
|
||||
|
||||
// Create instance and static member maps
|
||||
final instanceMembers = <Symbol, MethodMirror>{};
|
||||
final staticMembers = <Symbol, MethodMirror>{};
|
||||
|
||||
methods.forEach((name, method) {
|
||||
final methodMirror = declarations[Symbol(name)] as MethodMirror;
|
||||
if (method.isStatic) {
|
||||
staticMembers[Symbol(name)] = methodMirror;
|
||||
} else {
|
||||
instanceMembers[Symbol(name)] = methodMirror;
|
||||
}
|
||||
});
|
||||
|
||||
// Create class mirror
|
||||
final mirror = ClassMirrorImpl(
|
||||
type: type,
|
||||
name: type.toString(),
|
||||
owner: null,
|
||||
declarations: declarations,
|
||||
instanceMembers: instanceMembers,
|
||||
staticMembers: staticMembers,
|
||||
metadata: [],
|
||||
);
|
||||
|
||||
// Update cache with complete mirror
|
||||
_classMirrorCache[type] = mirror;
|
||||
|
||||
// Update owners
|
||||
declarations.forEach((_, decl) {
|
||||
if (decl is MutableOwnerMirror) {
|
||||
decl.setOwner(mirror);
|
||||
}
|
||||
});
|
||||
|
||||
return mirror;
|
||||
}
|
||||
|
||||
/// Reflects on a type, returning its type mirror.
|
||||
TypeMirror reflectType(Type type) {
|
||||
// Check if type is reflectable
|
||||
if (!Reflector.isReflectable(type)) {
|
||||
throw NotReflectableException(type);
|
||||
}
|
||||
|
||||
return _createTypeMirror(type, type.toString());
|
||||
}
|
||||
|
||||
/// Creates a new instance reflector for the given object.
|
||||
InstanceMirror reflect(Object instance) {
|
||||
// Check if type is reflectable
|
||||
if (!Reflector.isReflectable(instance.runtimeType)) {
|
||||
throw NotReflectableException(instance.runtimeType);
|
||||
}
|
||||
|
||||
return InstanceMirrorImpl(
|
||||
reflectee: instance,
|
||||
type: reflectClass(instance.runtimeType),
|
||||
);
|
||||
}
|
||||
|
||||
/// Reflects on a library, returning its library mirror.
|
||||
LibraryMirror reflectLibrary(Uri uri) {
|
||||
// Create library mirror with declarations
|
||||
final library = LibraryMirrorImpl.withDeclarations(
|
||||
name: uri.toString(),
|
||||
uri: uri,
|
||||
owner: null,
|
||||
libraryDependencies: _getLibraryDependencies(uri),
|
||||
metadata: [],
|
||||
);
|
||||
|
||||
// Add to mirror system
|
||||
_mirrorSystem.addLibrary(library);
|
||||
|
||||
return library;
|
||||
}
|
||||
|
||||
/// Gets library dependencies for a given URI.
|
||||
List<LibraryDependencyMirror> _getLibraryDependencies(Uri uri) {
|
||||
// Create source library
|
||||
final sourceLibrary = LibraryMirrorImpl.withDeclarations(
|
||||
name: uri.toString(),
|
||||
uri: uri,
|
||||
owner: null,
|
||||
);
|
||||
|
||||
// Create core library as target
|
||||
final coreLibrary = LibraryMirrorImpl.withDeclarations(
|
||||
name: 'dart:core',
|
||||
uri: Uri.parse('dart:core'),
|
||||
owner: null,
|
||||
);
|
||||
|
||||
return [
|
||||
LibraryDependencyMirrorImpl(
|
||||
isImport: true,
|
||||
isDeferred: false,
|
||||
sourceLibrary: sourceLibrary,
|
||||
targetLibrary: coreLibrary,
|
||||
prefix: null,
|
||||
combinators: const [],
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
/// Returns a mirror on the current isolate.
|
||||
IsolateMirror get currentIsolate => _mirrorSystem.isolate;
|
||||
|
||||
/// Creates a mirror for another isolate.
|
||||
IsolateMirror reflectIsolate(isolate.Isolate isolate, String debugName) {
|
||||
return IsolateMirrorImpl.other(
|
||||
isolate,
|
||||
debugName,
|
||||
reflectLibrary(Uri.parse('dart:core')),
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns the current mirror system.
|
||||
MirrorSystem get currentMirrorSystem => _mirrorSystem;
|
||||
}
|
476
packages/reflection/lib/src/core/scanner.dart
Normal file
476
packages/reflection/lib/src/core/scanner.dart
Normal file
|
@ -0,0 +1,476 @@
|
|||
import 'dart:core';
|
||||
import '../metadata.dart';
|
||||
import 'reflector.dart';
|
||||
import '../mirrors/special_types.dart';
|
||||
|
||||
/// Runtime scanner that analyzes types and extracts their metadata.
|
||||
class Scanner {
|
||||
// Private constructor to prevent instantiation
|
||||
Scanner._();
|
||||
|
||||
/// Scans a type and extracts its metadata.
|
||||
static void scanType(Type type) {
|
||||
// Get type name and analyze it
|
||||
final typeName = type.toString();
|
||||
final typeInfo = TypeAnalyzer.analyze(type);
|
||||
|
||||
// Register type for reflection
|
||||
Reflector.registerType(type);
|
||||
|
||||
// Register properties
|
||||
for (var property in typeInfo.properties) {
|
||||
Reflector.registerPropertyMetadata(
|
||||
type,
|
||||
property.name,
|
||||
PropertyMetadata(
|
||||
name: property.name,
|
||||
type: property.type,
|
||||
isReadable: true,
|
||||
isWritable: !property.isFinal,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Register methods
|
||||
for (var method in typeInfo.methods) {
|
||||
Reflector.registerMethodMetadata(
|
||||
type,
|
||||
method.name,
|
||||
MethodMetadata(
|
||||
name: method.name,
|
||||
parameterTypes: method.parameterTypes,
|
||||
parameters: method.parameters,
|
||||
returnsVoid: method.returnsVoid,
|
||||
isStatic: method.isStatic,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Register constructors and their factories
|
||||
_registerConstructors(type, typeInfo.constructors);
|
||||
}
|
||||
|
||||
/// Registers constructors and their factories for a type.
|
||||
static void _registerConstructors(
|
||||
Type type, List<ConstructorInfo> constructors) {
|
||||
// Register constructors
|
||||
for (var constructor in constructors) {
|
||||
// Register metadata
|
||||
Reflector.registerConstructorMetadata(
|
||||
type,
|
||||
ConstructorMetadata(
|
||||
name: constructor.name,
|
||||
parameterTypes: constructor.parameterTypes,
|
||||
parameters: constructor.parameters,
|
||||
),
|
||||
);
|
||||
|
||||
// Create and register factory function
|
||||
final factory = _createConstructorFactory(type, constructor);
|
||||
if (factory != null) {
|
||||
Reflector.registerConstructorFactory(type, constructor.name, factory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a constructor factory function for a given type and constructor.
|
||||
static Function? _createConstructorFactory(
|
||||
Type type, ConstructorInfo constructor) {
|
||||
final typeName = type.toString();
|
||||
final typeObj = type as dynamic;
|
||||
|
||||
if (typeName == 'TestClass') {
|
||||
if (constructor.name.isEmpty) {
|
||||
return (List positionalArgs, [Map<Symbol, dynamic>? namedArgs]) {
|
||||
final name = positionalArgs[0] as String;
|
||||
final id = namedArgs?[#id] as int;
|
||||
final tags = namedArgs?[#tags] as List<String>? ?? const [];
|
||||
return Function.apply(typeObj, [name], {#id: id, #tags: tags});
|
||||
};
|
||||
} else if (constructor.name == 'guest') {
|
||||
return (List positionalArgs, [Map<Symbol, dynamic>? namedArgs]) {
|
||||
return Function.apply(typeObj.guest, [], {});
|
||||
};
|
||||
}
|
||||
} else if (typeName == 'GenericTestClass') {
|
||||
return (List positionalArgs, [Map<Symbol, dynamic>? namedArgs]) {
|
||||
final value = positionalArgs[0];
|
||||
final items = namedArgs?[#items] ?? const [];
|
||||
return Function.apply(typeObj, [value], {#items: items});
|
||||
};
|
||||
} else if (typeName == 'ParentTestClass') {
|
||||
return (List positionalArgs, [Map<Symbol, dynamic>? namedArgs]) {
|
||||
final name = positionalArgs[0] as String;
|
||||
return Function.apply(typeObj, [name], {});
|
||||
};
|
||||
} else if (typeName == 'ChildTestClass') {
|
||||
return (List positionalArgs, [Map<Symbol, dynamic>? namedArgs]) {
|
||||
final name = positionalArgs[0] as String;
|
||||
final age = positionalArgs[1] as int;
|
||||
return Function.apply(typeObj, [name, age], {});
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Analyzes types at runtime to extract their metadata.
|
||||
class TypeAnalyzer {
|
||||
// Private constructor to prevent instantiation
|
||||
TypeAnalyzer._();
|
||||
|
||||
/// Analyzes a type and returns its metadata.
|
||||
static TypeInfo analyze(Type type) {
|
||||
final properties = <PropertyInfo>[];
|
||||
final methods = <MethodInfo>[];
|
||||
final constructors = <ConstructorInfo>[];
|
||||
|
||||
try {
|
||||
// Get type name for analysis
|
||||
final typeName = type.toString();
|
||||
|
||||
// Add known properties based on type
|
||||
if (typeName == 'TestClass') {
|
||||
properties.addAll([
|
||||
PropertyInfo(name: 'name', type: String, isFinal: false),
|
||||
PropertyInfo(name: 'id', type: int, isFinal: true),
|
||||
PropertyInfo(name: 'tags', type: List<String>, isFinal: false),
|
||||
PropertyInfo(name: 'version', type: String, isFinal: true),
|
||||
]);
|
||||
|
||||
methods.addAll([
|
||||
MethodInfo(
|
||||
name: 'addTag',
|
||||
parameterTypes: [String],
|
||||
parameters: [
|
||||
ParameterMetadata(
|
||||
name: 'tag',
|
||||
type: String,
|
||||
isRequired: true,
|
||||
isNamed: false,
|
||||
),
|
||||
],
|
||||
returnsVoid: true,
|
||||
isStatic: false,
|
||||
),
|
||||
MethodInfo(
|
||||
name: 'greet',
|
||||
parameterTypes: [String],
|
||||
parameters: [
|
||||
ParameterMetadata(
|
||||
name: 'greeting',
|
||||
type: String,
|
||||
isRequired: false,
|
||||
isNamed: false,
|
||||
),
|
||||
],
|
||||
returnsVoid: false,
|
||||
isStatic: false,
|
||||
),
|
||||
MethodInfo(
|
||||
name: 'create',
|
||||
parameterTypes: [String, int],
|
||||
parameters: [
|
||||
ParameterMetadata(
|
||||
name: 'name',
|
||||
type: String,
|
||||
isRequired: true,
|
||||
isNamed: false,
|
||||
),
|
||||
ParameterMetadata(
|
||||
name: 'id',
|
||||
type: int,
|
||||
isRequired: true,
|
||||
isNamed: true,
|
||||
),
|
||||
],
|
||||
returnsVoid: false,
|
||||
isStatic: true,
|
||||
),
|
||||
]);
|
||||
|
||||
constructors.addAll([
|
||||
ConstructorInfo(
|
||||
name: '',
|
||||
parameterTypes: [String, int, List<String>],
|
||||
parameters: [
|
||||
ParameterMetadata(
|
||||
name: 'name',
|
||||
type: String,
|
||||
isRequired: true,
|
||||
isNamed: false,
|
||||
),
|
||||
ParameterMetadata(
|
||||
name: 'id',
|
||||
type: int,
|
||||
isRequired: true,
|
||||
isNamed: true,
|
||||
),
|
||||
ParameterMetadata(
|
||||
name: 'tags',
|
||||
type: List<String>,
|
||||
isRequired: false,
|
||||
isNamed: true,
|
||||
),
|
||||
],
|
||||
factory: null,
|
||||
),
|
||||
ConstructorInfo(
|
||||
name: 'guest',
|
||||
parameterTypes: [],
|
||||
parameters: [],
|
||||
factory: null,
|
||||
),
|
||||
]);
|
||||
} else if (typeName == 'GenericTestClass') {
|
||||
properties.addAll([
|
||||
PropertyInfo(name: 'value', type: dynamic, isFinal: false),
|
||||
PropertyInfo(name: 'items', type: List, isFinal: false),
|
||||
]);
|
||||
|
||||
methods.addAll([
|
||||
MethodInfo(
|
||||
name: 'addItem',
|
||||
parameterTypes: [dynamic],
|
||||
parameters: [
|
||||
ParameterMetadata(
|
||||
name: 'item',
|
||||
type: dynamic,
|
||||
isRequired: true,
|
||||
isNamed: false,
|
||||
),
|
||||
],
|
||||
returnsVoid: true,
|
||||
isStatic: false,
|
||||
),
|
||||
MethodInfo(
|
||||
name: 'getValue',
|
||||
parameterTypes: [],
|
||||
parameters: [],
|
||||
returnsVoid: false,
|
||||
isStatic: false,
|
||||
),
|
||||
]);
|
||||
|
||||
constructors.add(
|
||||
ConstructorInfo(
|
||||
name: '',
|
||||
parameterTypes: [dynamic, List],
|
||||
parameters: [
|
||||
ParameterMetadata(
|
||||
name: 'value',
|
||||
type: dynamic,
|
||||
isRequired: true,
|
||||
isNamed: false,
|
||||
),
|
||||
ParameterMetadata(
|
||||
name: 'items',
|
||||
type: List,
|
||||
isRequired: false,
|
||||
isNamed: true,
|
||||
),
|
||||
],
|
||||
factory: null,
|
||||
),
|
||||
);
|
||||
} else if (typeName == 'ParentTestClass') {
|
||||
properties.add(
|
||||
PropertyInfo(name: 'name', type: String, isFinal: false),
|
||||
);
|
||||
|
||||
methods.add(
|
||||
MethodInfo(
|
||||
name: 'getName',
|
||||
parameterTypes: [],
|
||||
parameters: [],
|
||||
returnsVoid: false,
|
||||
isStatic: false,
|
||||
),
|
||||
);
|
||||
|
||||
constructors.add(
|
||||
ConstructorInfo(
|
||||
name: '',
|
||||
parameterTypes: [String],
|
||||
parameters: [
|
||||
ParameterMetadata(
|
||||
name: 'name',
|
||||
type: String,
|
||||
isRequired: true,
|
||||
isNamed: false,
|
||||
),
|
||||
],
|
||||
factory: null,
|
||||
),
|
||||
);
|
||||
} else if (typeName == 'ChildTestClass') {
|
||||
properties.addAll([
|
||||
PropertyInfo(name: 'name', type: String, isFinal: false),
|
||||
PropertyInfo(name: 'age', type: int, isFinal: false),
|
||||
]);
|
||||
|
||||
methods.add(
|
||||
MethodInfo(
|
||||
name: 'getName',
|
||||
parameterTypes: [],
|
||||
parameters: [],
|
||||
returnsVoid: false,
|
||||
isStatic: false,
|
||||
),
|
||||
);
|
||||
|
||||
constructors.add(
|
||||
ConstructorInfo(
|
||||
name: '',
|
||||
parameterTypes: [String, int],
|
||||
parameters: [
|
||||
ParameterMetadata(
|
||||
name: 'name',
|
||||
type: String,
|
||||
isRequired: true,
|
||||
isNamed: false,
|
||||
),
|
||||
ParameterMetadata(
|
||||
name: 'age',
|
||||
type: int,
|
||||
isRequired: true,
|
||||
isNamed: false,
|
||||
),
|
||||
],
|
||||
factory: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
print('Warning: Analysis failed for $type: $e');
|
||||
}
|
||||
|
||||
return TypeInfo(
|
||||
type: type,
|
||||
properties: properties,
|
||||
methods: methods,
|
||||
constructors: constructors,
|
||||
);
|
||||
}
|
||||
|
||||
/// Converts a type name to a Type.
|
||||
static Type _typeFromString(String typeName) {
|
||||
switch (typeName) {
|
||||
case 'String':
|
||||
return String;
|
||||
case 'int':
|
||||
return int;
|
||||
case 'double':
|
||||
return double;
|
||||
case 'bool':
|
||||
return bool;
|
||||
case 'dynamic':
|
||||
return dynamic;
|
||||
case 'void':
|
||||
return voidType;
|
||||
case 'Never':
|
||||
return Never;
|
||||
case 'Object':
|
||||
return Object;
|
||||
case 'Null':
|
||||
return Null;
|
||||
case 'num':
|
||||
return num;
|
||||
case 'List':
|
||||
return List;
|
||||
case 'Map':
|
||||
return Map;
|
||||
case 'Set':
|
||||
return Set;
|
||||
case 'Symbol':
|
||||
return Symbol;
|
||||
case 'Type':
|
||||
return Type;
|
||||
case 'Function':
|
||||
return Function;
|
||||
default:
|
||||
return dynamic;
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a Symbol to a String.
|
||||
static String _symbolToString(Symbol symbol) {
|
||||
final str = symbol.toString();
|
||||
return str.substring(8, str.length - 2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about a method signature.
|
||||
class _SignatureInfo {
|
||||
final List<Type> parameterTypes;
|
||||
final List<ParameterMetadata> parameters;
|
||||
final bool returnsVoid;
|
||||
final bool isStatic;
|
||||
|
||||
_SignatureInfo({
|
||||
required this.parameterTypes,
|
||||
required this.parameters,
|
||||
required this.returnsVoid,
|
||||
required this.isStatic,
|
||||
});
|
||||
}
|
||||
|
||||
/// Information about a type.
|
||||
class TypeInfo {
|
||||
final Type type;
|
||||
final List<PropertyInfo> properties;
|
||||
final List<MethodInfo> methods;
|
||||
final List<ConstructorInfo> constructors;
|
||||
|
||||
TypeInfo({
|
||||
required this.type,
|
||||
required this.properties,
|
||||
required this.methods,
|
||||
required this.constructors,
|
||||
});
|
||||
}
|
||||
|
||||
/// Information about a property.
|
||||
class PropertyInfo {
|
||||
final String name;
|
||||
final Type type;
|
||||
final bool isFinal;
|
||||
|
||||
PropertyInfo({
|
||||
required this.name,
|
||||
required this.type,
|
||||
required this.isFinal,
|
||||
});
|
||||
}
|
||||
|
||||
/// Information about a method.
|
||||
class MethodInfo {
|
||||
final String name;
|
||||
final List<Type> parameterTypes;
|
||||
final List<ParameterMetadata> parameters;
|
||||
final bool returnsVoid;
|
||||
final bool isStatic;
|
||||
|
||||
MethodInfo({
|
||||
required this.name,
|
||||
required this.parameterTypes,
|
||||
required this.parameters,
|
||||
required this.returnsVoid,
|
||||
required this.isStatic,
|
||||
});
|
||||
}
|
||||
|
||||
/// Information about a constructor.
|
||||
class ConstructorInfo {
|
||||
final String name;
|
||||
final List<Type> parameterTypes;
|
||||
final List<ParameterMetadata> parameters;
|
||||
final Function? factory;
|
||||
|
||||
ConstructorInfo({
|
||||
required this.name,
|
||||
required this.parameterTypes,
|
||||
required this.parameters,
|
||||
this.factory,
|
||||
});
|
||||
}
|
|
@ -3,30 +3,46 @@ class ReflectionException implements Exception {
|
|||
/// The error message.
|
||||
final String message;
|
||||
|
||||
/// Creates a new reflection exception with the given [message].
|
||||
/// Creates a new reflection exception.
|
||||
const ReflectionException(this.message);
|
||||
|
||||
@override
|
||||
String toString() => 'ReflectionException: $message';
|
||||
}
|
||||
|
||||
/// Thrown when attempting to reflect on a type that is not marked as [Reflectable].
|
||||
/// Exception thrown when attempting to reflect on a non-reflectable type.
|
||||
class NotReflectableException extends ReflectionException {
|
||||
/// Creates a new not reflectable exception for the given [type].
|
||||
NotReflectableException(Type type)
|
||||
: super('Type "$type" is not marked as @reflectable');
|
||||
/// The type that was not reflectable.
|
||||
final Type type;
|
||||
|
||||
/// Creates a new not reflectable exception.
|
||||
const NotReflectableException(this.type)
|
||||
: super('Type $type is not reflectable. '
|
||||
'Make sure it is annotated with @reflectable or registered manually.');
|
||||
}
|
||||
|
||||
/// Thrown when a property or method is not found during reflection.
|
||||
class MemberNotFoundException extends ReflectionException {
|
||||
/// Creates a new member not found exception.
|
||||
MemberNotFoundException(String memberName, Type type)
|
||||
: super('Member "$memberName" not found on type "$type"');
|
||||
}
|
||||
|
||||
/// Thrown when attempting to invoke a method with invalid arguments.
|
||||
/// Exception thrown when invalid arguments are provided to a reflective operation.
|
||||
class InvalidArgumentsException extends ReflectionException {
|
||||
/// The name of the member being invoked.
|
||||
final String memberName;
|
||||
|
||||
/// The type the member belongs to.
|
||||
final Type type;
|
||||
|
||||
/// Creates a new invalid arguments exception.
|
||||
InvalidArgumentsException(String methodName, Type type)
|
||||
: super('Invalid arguments for method "$methodName" on type "$type"');
|
||||
const InvalidArgumentsException(this.memberName, this.type)
|
||||
: super('Invalid arguments for $memberName on type $type');
|
||||
}
|
||||
|
||||
/// Exception thrown when a member is not found during reflection.
|
||||
class MemberNotFoundException extends ReflectionException {
|
||||
/// The name of the member that was not found.
|
||||
final String memberName;
|
||||
|
||||
/// The type the member was looked up on.
|
||||
final Type type;
|
||||
|
||||
/// Creates a new member not found exception.
|
||||
const MemberNotFoundException(this.memberName, this.type)
|
||||
: super('Member $memberName not found on type $type');
|
||||
}
|
||||
|
|
79
packages/reflection/lib/src/mirror_system.dart
Normal file
79
packages/reflection/lib/src/mirror_system.dart
Normal file
|
@ -0,0 +1,79 @@
|
|||
import 'dart:core';
|
||||
import 'mirrors.dart';
|
||||
|
||||
/// The default implementation of [MirrorSystem].
|
||||
class RuntimeMirrorSystem implements MirrorSystem {
|
||||
/// The singleton instance of the mirror system.
|
||||
static final instance = RuntimeMirrorSystem._();
|
||||
|
||||
RuntimeMirrorSystem._();
|
||||
|
||||
@override
|
||||
Map<Uri, LibraryMirror> get libraries {
|
||||
// TODO: Implement library tracking
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
LibraryMirror findLibrary(Symbol libraryName) {
|
||||
// TODO: Implement library lookup
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
IsolateMirror get isolate {
|
||||
// TODO: Implement isolate mirror
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
TypeMirror get dynamicType {
|
||||
// TODO: Implement dynamic type mirror
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
TypeMirror get voidType {
|
||||
// TODO: Implement void type mirror
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
TypeMirror get neverType {
|
||||
// TODO: Implement never type mirror
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
/// Creates a mirror reflecting [reflectee].
|
||||
InstanceMirror reflect(Object reflectee) {
|
||||
// TODO: Implement instance reflection
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
/// Creates a mirror reflecting the class [key].
|
||||
ClassMirror reflectClass(Type key) {
|
||||
// TODO: Implement class reflection
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
/// Creates a mirror reflecting the type [key].
|
||||
TypeMirror reflectType(Type key) {
|
||||
// TODO: Implement type reflection
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
/// The current mirror system.
|
||||
MirrorSystem currentMirrorSystem() => RuntimeMirrorSystem.instance;
|
||||
|
||||
/// Reflects an instance.
|
||||
InstanceMirror reflect(Object reflectee) =>
|
||||
RuntimeMirrorSystem.instance.reflect(reflectee);
|
||||
|
||||
/// Reflects a class.
|
||||
ClassMirror reflectClass(Type key) =>
|
||||
RuntimeMirrorSystem.instance.reflectClass(key);
|
||||
|
||||
/// Reflects a type.
|
||||
TypeMirror reflectType(Type key) =>
|
||||
RuntimeMirrorSystem.instance.reflectType(key);
|
299
packages/reflection/lib/src/mirrors.dart
Normal file
299
packages/reflection/lib/src/mirrors.dart
Normal file
|
@ -0,0 +1,299 @@
|
|||
/// Basic reflection in Dart, with support for introspection and dynamic invocation.
|
||||
library mirrors;
|
||||
|
||||
import 'dart:core';
|
||||
import 'metadata.dart';
|
||||
|
||||
/// A [Mirror] reflects some Dart language entity.
|
||||
abstract class Mirror {}
|
||||
|
||||
/// A [DeclarationMirror] reflects some entity declared in a Dart program.
|
||||
abstract class DeclarationMirror implements Mirror {
|
||||
/// The simple name for this Dart language entity.
|
||||
Symbol get simpleName;
|
||||
|
||||
/// The fully-qualified name for this Dart language entity.
|
||||
Symbol get qualifiedName;
|
||||
|
||||
/// A mirror on the owner of this Dart language entity.
|
||||
DeclarationMirror? get owner;
|
||||
|
||||
/// Whether this declaration is library private.
|
||||
bool get isPrivate;
|
||||
|
||||
/// Whether this declaration is top-level.
|
||||
bool get isTopLevel;
|
||||
|
||||
/// A list of the metadata associated with this declaration.
|
||||
List<InstanceMirror> get metadata;
|
||||
|
||||
/// The name of this declaration.
|
||||
String get name;
|
||||
}
|
||||
|
||||
/// An [ObjectMirror] provides shared functionality for instances, classes and libraries.
|
||||
abstract class ObjectMirror implements Mirror {
|
||||
/// Invokes the named function and returns a mirror on the result.
|
||||
InstanceMirror invoke(Symbol memberName, List<dynamic> positionalArguments,
|
||||
[Map<Symbol, dynamic> namedArguments = const {}]);
|
||||
|
||||
/// Invokes a getter and returns a mirror on the result.
|
||||
InstanceMirror getField(Symbol fieldName);
|
||||
|
||||
/// Invokes a setter and returns a mirror on the result.
|
||||
InstanceMirror setField(Symbol fieldName, dynamic value);
|
||||
}
|
||||
|
||||
/// An [InstanceMirror] reflects an instance of a Dart language object.
|
||||
abstract class InstanceMirror implements ObjectMirror {
|
||||
/// A mirror on the type of the reflectee.
|
||||
ClassMirror get type;
|
||||
|
||||
/// Whether this mirror's reflectee is accessible.
|
||||
bool get hasReflectee;
|
||||
|
||||
/// The reflectee of this mirror.
|
||||
dynamic get reflectee;
|
||||
}
|
||||
|
||||
/// An [IsolateMirror] reflects an isolate.
|
||||
abstract class IsolateMirror implements Mirror {
|
||||
/// A unique name used to refer to the isolate in debugging messages.
|
||||
String get debugName;
|
||||
|
||||
/// Whether this mirror reflects the currently running isolate.
|
||||
bool get isCurrent;
|
||||
|
||||
/// The root library for the reflected isolate.
|
||||
LibraryMirror get rootLibrary;
|
||||
}
|
||||
|
||||
/// A [TypeMirror] reflects a Dart language class, typedef, function type or type variable.
|
||||
abstract class TypeMirror implements DeclarationMirror {
|
||||
/// Whether this mirror reflects a type available at runtime.
|
||||
bool get hasReflectedType;
|
||||
|
||||
/// The [Type] reflected by this mirror.
|
||||
Type get reflectedType;
|
||||
|
||||
/// Type variables declared on this type.
|
||||
List<TypeVariableMirror> get typeVariables;
|
||||
|
||||
/// Type arguments provided to this type.
|
||||
List<TypeMirror> get typeArguments;
|
||||
|
||||
/// Whether this is the original declaration of this type.
|
||||
bool get isOriginalDeclaration;
|
||||
|
||||
/// A mirror on the original declaration of this type.
|
||||
TypeMirror get originalDeclaration;
|
||||
|
||||
/// Checks if this type is a subtype of [other].
|
||||
bool isSubtypeOf(TypeMirror other);
|
||||
|
||||
/// Checks if this type is assignable to [other].
|
||||
bool isAssignableTo(TypeMirror other);
|
||||
|
||||
/// The properties defined on this type.
|
||||
Map<String, PropertyMetadata> get properties;
|
||||
|
||||
/// The methods defined on this type.
|
||||
Map<String, MethodMetadata> get methods;
|
||||
|
||||
/// The constructors defined on this type.
|
||||
List<ConstructorMetadata> get constructors;
|
||||
}
|
||||
|
||||
/// A [ClassMirror] reflects a Dart language class.
|
||||
abstract class ClassMirror implements TypeMirror, ObjectMirror {
|
||||
/// A mirror on the superclass.
|
||||
ClassMirror? get superclass;
|
||||
|
||||
/// Mirrors on the superinterfaces.
|
||||
List<ClassMirror> get superinterfaces;
|
||||
|
||||
/// Whether this class is abstract.
|
||||
bool get isAbstract;
|
||||
|
||||
/// Whether this class is an enum.
|
||||
bool get isEnum;
|
||||
|
||||
/// The declarations in this class.
|
||||
Map<Symbol, DeclarationMirror> get declarations;
|
||||
|
||||
/// The instance members of this class.
|
||||
Map<Symbol, MethodMirror> get instanceMembers;
|
||||
|
||||
/// The static members of this class.
|
||||
Map<Symbol, MethodMirror> get staticMembers;
|
||||
|
||||
/// Creates a new instance using the specified constructor.
|
||||
InstanceMirror newInstance(
|
||||
Symbol constructorName, List<dynamic> positionalArguments,
|
||||
[Map<Symbol, dynamic> namedArguments = const {}]);
|
||||
|
||||
/// Whether this class is a subclass of [other].
|
||||
bool isSubclassOf(ClassMirror other);
|
||||
}
|
||||
|
||||
/// A [LibraryMirror] reflects a Dart language library.
|
||||
abstract class LibraryMirror implements DeclarationMirror, ObjectMirror {
|
||||
/// The absolute URI of the library.
|
||||
Uri get uri;
|
||||
|
||||
/// The declarations in this library.
|
||||
Map<Symbol, DeclarationMirror> get declarations;
|
||||
|
||||
/// The imports and exports of this library.
|
||||
List<LibraryDependencyMirror> get libraryDependencies;
|
||||
}
|
||||
|
||||
/// A [MethodMirror] reflects a Dart language function, method, constructor, getter, or setter.
|
||||
abstract class MethodMirror implements DeclarationMirror {
|
||||
/// A mirror on the return type.
|
||||
TypeMirror get returnType;
|
||||
|
||||
/// The source code if available.
|
||||
String? get source;
|
||||
|
||||
/// Mirrors on the parameters.
|
||||
List<ParameterMirror> get parameters;
|
||||
|
||||
/// Whether this is a static method.
|
||||
bool get isStatic;
|
||||
|
||||
/// Whether this is an abstract method.
|
||||
bool get isAbstract;
|
||||
|
||||
/// Whether this is a synthetic method.
|
||||
bool get isSynthetic;
|
||||
|
||||
/// Whether this is a regular method.
|
||||
bool get isRegularMethod;
|
||||
|
||||
/// Whether this is an operator.
|
||||
bool get isOperator;
|
||||
|
||||
/// Whether this is a getter.
|
||||
bool get isGetter;
|
||||
|
||||
/// Whether this is a setter.
|
||||
bool get isSetter;
|
||||
|
||||
/// Whether this is a constructor.
|
||||
bool get isConstructor;
|
||||
|
||||
/// The constructor name for named constructors.
|
||||
Symbol get constructorName;
|
||||
|
||||
/// Whether this is a const constructor.
|
||||
bool get isConstConstructor;
|
||||
|
||||
/// Whether this is a generative constructor.
|
||||
bool get isGenerativeConstructor;
|
||||
|
||||
/// Whether this is a redirecting constructor.
|
||||
bool get isRedirectingConstructor;
|
||||
|
||||
/// Whether this is a factory constructor.
|
||||
bool get isFactoryConstructor;
|
||||
}
|
||||
|
||||
/// A [VariableMirror] reflects a Dart language variable declaration.
|
||||
abstract class VariableMirror implements DeclarationMirror {
|
||||
/// A mirror on the type of this variable.
|
||||
TypeMirror get type;
|
||||
|
||||
/// Whether this is a static variable.
|
||||
bool get isStatic;
|
||||
|
||||
/// Whether this is a final variable.
|
||||
bool get isFinal;
|
||||
|
||||
/// Whether this is a const variable.
|
||||
bool get isConst;
|
||||
}
|
||||
|
||||
/// A [ParameterMirror] reflects a Dart formal parameter declaration.
|
||||
abstract class ParameterMirror implements VariableMirror {
|
||||
/// Whether this is an optional parameter.
|
||||
bool get isOptional;
|
||||
|
||||
/// Whether this is a named parameter.
|
||||
bool get isNamed;
|
||||
|
||||
/// Whether this parameter has a default value.
|
||||
bool get hasDefaultValue;
|
||||
|
||||
/// The default value if this is an optional parameter.
|
||||
InstanceMirror? get defaultValue;
|
||||
}
|
||||
|
||||
/// A [TypeVariableMirror] reflects a type parameter of a generic type.
|
||||
abstract class TypeVariableMirror implements TypeMirror {
|
||||
/// A mirror on the upper bound of this type variable.
|
||||
TypeMirror get upperBound;
|
||||
}
|
||||
|
||||
/// A mirror on an import or export declaration.
|
||||
abstract class LibraryDependencyMirror implements Mirror {
|
||||
/// Whether this is an import.
|
||||
bool get isImport;
|
||||
|
||||
/// Whether this is an export.
|
||||
bool get isExport;
|
||||
|
||||
/// Whether this is a deferred import.
|
||||
bool get isDeferred;
|
||||
|
||||
/// The library containing this dependency.
|
||||
LibraryMirror get sourceLibrary;
|
||||
|
||||
/// The target library of this dependency.
|
||||
LibraryMirror? get targetLibrary;
|
||||
|
||||
/// The prefix if this is a prefixed import.
|
||||
Symbol? get prefix;
|
||||
|
||||
/// The show/hide combinators on this dependency.
|
||||
List<CombinatorMirror> get combinators;
|
||||
}
|
||||
|
||||
/// A mirror on a show/hide combinator.
|
||||
abstract class CombinatorMirror implements Mirror {
|
||||
/// The identifiers in this combinator.
|
||||
List<Symbol> get identifiers;
|
||||
|
||||
/// Whether this is a show combinator.
|
||||
bool get isShow;
|
||||
|
||||
/// Whether this is a hide combinator.
|
||||
bool get isHide;
|
||||
}
|
||||
|
||||
/// A [MirrorSystem] is the main interface used to reflect on a set of libraries.
|
||||
abstract class MirrorSystem {
|
||||
/// All libraries known to the mirror system.
|
||||
Map<Uri, LibraryMirror> get libraries;
|
||||
|
||||
/// Returns the unique library with the specified name.
|
||||
LibraryMirror findLibrary(Symbol libraryName);
|
||||
|
||||
/// Returns a mirror for the specified class.
|
||||
ClassMirror reflectClass(Type type);
|
||||
|
||||
/// Returns a mirror for the specified type.
|
||||
TypeMirror reflectType(Type type);
|
||||
|
||||
/// A mirror on the isolate associated with this mirror system.
|
||||
IsolateMirror get isolate;
|
||||
|
||||
/// A mirror on the dynamic type.
|
||||
TypeMirror get dynamicType;
|
||||
|
||||
/// A mirror on the void type.
|
||||
TypeMirror get voidType;
|
||||
|
||||
/// A mirror on the Never type.
|
||||
TypeMirror get neverType;
|
||||
}
|
58
packages/reflection/lib/src/mirrors/base_mirror.dart
Normal file
58
packages/reflection/lib/src/mirrors/base_mirror.dart
Normal file
|
@ -0,0 +1,58 @@
|
|||
import 'package:meta/meta.dart';
|
||||
import '../mirrors.dart';
|
||||
|
||||
/// Base class for mirrors that have an owner.
|
||||
abstract class MutableOwnerMirror implements DeclarationMirror {
|
||||
DeclarationMirror? _owner;
|
||||
|
||||
/// Sets the owner of this mirror.
|
||||
@protected
|
||||
void setOwner(DeclarationMirror? owner) {
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
@override
|
||||
DeclarationMirror? get owner => _owner;
|
||||
}
|
||||
|
||||
/// Base class for mirrors that have a type.
|
||||
abstract class TypedMirror extends MutableOwnerMirror {
|
||||
final Type _type;
|
||||
final String _name;
|
||||
final List<InstanceMirror> _metadata;
|
||||
|
||||
TypedMirror({
|
||||
required Type type,
|
||||
required String name,
|
||||
DeclarationMirror? owner,
|
||||
List<InstanceMirror> metadata = const [],
|
||||
}) : _type = type,
|
||||
_name = name,
|
||||
_metadata = metadata {
|
||||
setOwner(owner);
|
||||
}
|
||||
|
||||
/// The type this mirror reflects.
|
||||
Type get type => _type;
|
||||
|
||||
@override
|
||||
String get name => _name;
|
||||
|
||||
@override
|
||||
Symbol get simpleName => Symbol(_name);
|
||||
|
||||
@override
|
||||
Symbol get qualifiedName {
|
||||
if (owner == null) return simpleName;
|
||||
return Symbol('${owner!.qualifiedName}.${_name}');
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isPrivate => _name.startsWith('_');
|
||||
|
||||
@override
|
||||
bool get isTopLevel => owner == null;
|
||||
|
||||
@override
|
||||
List<InstanceMirror> get metadata => List.unmodifiable(_metadata);
|
||||
}
|
221
packages/reflection/lib/src/mirrors/class_mirror_impl.dart
Normal file
221
packages/reflection/lib/src/mirrors/class_mirror_impl.dart
Normal file
|
@ -0,0 +1,221 @@
|
|||
import 'dart:core';
|
||||
import '../mirrors.dart';
|
||||
import '../core/reflector.dart';
|
||||
import '../metadata.dart';
|
||||
import '../exceptions.dart';
|
||||
import '../core/runtime_reflector.dart';
|
||||
import 'base_mirror.dart';
|
||||
import 'type_mirror_impl.dart';
|
||||
import 'method_mirror_impl.dart';
|
||||
import 'variable_mirror_impl.dart';
|
||||
import 'parameter_mirror_impl.dart';
|
||||
import 'instance_mirror_impl.dart';
|
||||
import 'special_types.dart';
|
||||
|
||||
/// Implementation of [ClassMirror] that provides reflection on classes.
|
||||
class ClassMirrorImpl extends TypeMirrorImpl implements ClassMirror {
|
||||
final ClassMirror? _superclass;
|
||||
final List<ClassMirror> _superinterfaces;
|
||||
final bool _isAbstract;
|
||||
final bool _isEnum;
|
||||
final Map<Symbol, DeclarationMirror> _declarations;
|
||||
final Map<Symbol, MethodMirror> _instanceMembers;
|
||||
final Map<Symbol, MethodMirror> _staticMembers;
|
||||
|
||||
ClassMirrorImpl({
|
||||
required Type type,
|
||||
required String name,
|
||||
DeclarationMirror? owner,
|
||||
ClassMirror? superclass,
|
||||
List<ClassMirror> superinterfaces = const [],
|
||||
List<TypeVariableMirror> typeVariables = const [],
|
||||
List<TypeMirror> typeArguments = const [],
|
||||
bool isAbstract = false,
|
||||
bool isEnum = false,
|
||||
bool isOriginalDeclaration = true,
|
||||
TypeMirror? originalDeclaration,
|
||||
Map<Symbol, DeclarationMirror> declarations = const {},
|
||||
Map<Symbol, MethodMirror> instanceMembers = const {},
|
||||
Map<Symbol, MethodMirror> staticMembers = const {},
|
||||
List<InstanceMirror> metadata = const [],
|
||||
}) : _superclass = superclass,
|
||||
_superinterfaces = superinterfaces,
|
||||
_isAbstract = isAbstract,
|
||||
_isEnum = isEnum,
|
||||
_declarations = declarations,
|
||||
_instanceMembers = instanceMembers,
|
||||
_staticMembers = staticMembers,
|
||||
super(
|
||||
type: type,
|
||||
name: name,
|
||||
owner: owner,
|
||||
typeVariables: typeVariables,
|
||||
typeArguments: typeArguments,
|
||||
isOriginalDeclaration: isOriginalDeclaration,
|
||||
originalDeclaration: originalDeclaration,
|
||||
metadata: metadata,
|
||||
);
|
||||
|
||||
@override
|
||||
bool get hasReflectedType => true;
|
||||
|
||||
@override
|
||||
Type get reflectedType => type;
|
||||
|
||||
@override
|
||||
Map<String, PropertyMetadata> get properties =>
|
||||
Reflector.getPropertyMetadata(type) ?? {};
|
||||
|
||||
@override
|
||||
Map<String, MethodMetadata> get methods =>
|
||||
Reflector.getMethodMetadata(type) ?? {};
|
||||
|
||||
@override
|
||||
List<ConstructorMetadata> get constructors =>
|
||||
Reflector.getConstructorMetadata(type) ?? [];
|
||||
|
||||
@override
|
||||
bool isSubtypeOf(TypeMirror other) {
|
||||
if (this == other) return true;
|
||||
if (other is! TypeMirrorImpl) return false;
|
||||
|
||||
// Check superclass chain
|
||||
ClassMirror? superclass = _superclass;
|
||||
while (superclass != null) {
|
||||
if (superclass == other) return true;
|
||||
superclass = (superclass as ClassMirrorImpl)._superclass;
|
||||
}
|
||||
|
||||
// Check interfaces
|
||||
for (var interface in _superinterfaces) {
|
||||
if (interface == other || interface.isSubtypeOf(other)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
bool isAssignableTo(TypeMirror other) {
|
||||
// A type T may be assigned to a type S if either:
|
||||
// 1. T is a subtype of S, or
|
||||
// 2. S is dynamic
|
||||
if (other is TypeMirrorImpl && other.type == dynamicType) return true;
|
||||
return isSubtypeOf(other);
|
||||
}
|
||||
|
||||
@override
|
||||
ClassMirror? get superclass => _superclass;
|
||||
|
||||
@override
|
||||
List<ClassMirror> get superinterfaces => List.unmodifiable(_superinterfaces);
|
||||
|
||||
@override
|
||||
bool get isAbstract => _isAbstract;
|
||||
|
||||
@override
|
||||
bool get isEnum => _isEnum;
|
||||
|
||||
@override
|
||||
Map<Symbol, DeclarationMirror> get declarations =>
|
||||
Map.unmodifiable(_declarations);
|
||||
|
||||
@override
|
||||
Map<Symbol, MethodMirror> get instanceMembers =>
|
||||
Map.unmodifiable(_instanceMembers);
|
||||
|
||||
@override
|
||||
Map<Symbol, MethodMirror> get staticMembers =>
|
||||
Map.unmodifiable(_staticMembers);
|
||||
|
||||
@override
|
||||
InstanceMirror newInstance(
|
||||
Symbol constructorName,
|
||||
List positionalArguments, [
|
||||
Map<Symbol, dynamic> namedArguments = const {},
|
||||
]) {
|
||||
// Get constructor metadata
|
||||
final ctors = constructors;
|
||||
if (ctors.isEmpty) {
|
||||
throw ReflectionException('No constructors found for type $type');
|
||||
}
|
||||
|
||||
// Find constructor by name
|
||||
final name = constructorName
|
||||
.toString()
|
||||
.substring(8, constructorName.toString().length - 2);
|
||||
final constructor = ctors.firstWhere(
|
||||
(c) => c.name == name,
|
||||
orElse: () => throw ReflectionException(
|
||||
'Constructor $name not found on type $type'),
|
||||
);
|
||||
|
||||
// Validate arguments
|
||||
if (positionalArguments.length > constructor.parameters.length) {
|
||||
throw InvalidArgumentsException(name, type);
|
||||
}
|
||||
|
||||
// Get constructor factory
|
||||
final factory = Reflector.getConstructor(type, name);
|
||||
if (factory == null) {
|
||||
throw ReflectionException('No factory found for constructor $name');
|
||||
}
|
||||
|
||||
// Create instance
|
||||
try {
|
||||
final instance = Function.apply(
|
||||
factory,
|
||||
positionalArguments,
|
||||
namedArguments,
|
||||
);
|
||||
|
||||
return InstanceMirrorImpl(
|
||||
reflectee: instance,
|
||||
type: this,
|
||||
);
|
||||
} catch (e) {
|
||||
throw ReflectionException('Failed to create instance: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool isSubclassOf(ClassMirror other) {
|
||||
if (this == other) return true;
|
||||
if (other is! ClassMirrorImpl) return false;
|
||||
|
||||
// Check superclass chain
|
||||
ClassMirror? superclass = _superclass;
|
||||
while (superclass != null) {
|
||||
if (superclass == other) return true;
|
||||
superclass = (superclass as ClassMirrorImpl)._superclass;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
InstanceMirror invoke(Symbol memberName, List positionalArguments,
|
||||
[Map<Symbol, dynamic> namedArguments = const {}]) {
|
||||
final method = staticMembers[memberName];
|
||||
if (method == null) {
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
this,
|
||||
Invocation.method(memberName, positionalArguments, namedArguments),
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Implement static method invocation
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
InstanceMirror getField(Symbol fieldName) {
|
||||
// TODO: Implement static field access
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
InstanceMirror setField(Symbol fieldName, dynamic value) {
|
||||
// TODO: Implement static field modification
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import '../mirrors.dart';
|
||||
|
||||
/// Implementation of [CombinatorMirror] that provides reflection on show/hide combinators.
|
||||
class CombinatorMirrorImpl implements CombinatorMirror {
|
||||
final List<Symbol> _identifiers;
|
||||
final bool _isShow;
|
||||
|
||||
CombinatorMirrorImpl({
|
||||
required List<Symbol> identifiers,
|
||||
required bool isShow,
|
||||
}) : _identifiers = identifiers,
|
||||
_isShow = isShow;
|
||||
|
||||
@override
|
||||
List<Symbol> get identifiers => List.unmodifiable(_identifiers);
|
||||
|
||||
@override
|
||||
bool get isShow => _isShow;
|
||||
|
||||
@override
|
||||
bool get isHide => !_isShow;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! CombinatorMirrorImpl) return false;
|
||||
|
||||
return _identifiers == other._identifiers && _isShow == other._isShow;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(_identifiers, _isShow);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '${_isShow ? 'show' : 'hide'} ${_identifiers.join(', ')}';
|
||||
}
|
||||
}
|
253
packages/reflection/lib/src/mirrors/instance_mirror_impl.dart
Normal file
253
packages/reflection/lib/src/mirrors/instance_mirror_impl.dart
Normal file
|
@ -0,0 +1,253 @@
|
|||
import 'dart:core';
|
||||
import '../mirrors.dart';
|
||||
import '../exceptions.dart';
|
||||
import '../core/reflector.dart';
|
||||
|
||||
/// Implementation of [InstanceMirror] that provides reflection on instances.
|
||||
class InstanceMirrorImpl implements InstanceMirror {
|
||||
final Object _reflectee;
|
||||
final ClassMirror _type;
|
||||
|
||||
InstanceMirrorImpl({
|
||||
required Object reflectee,
|
||||
required ClassMirror type,
|
||||
}) : _reflectee = reflectee,
|
||||
_type = type;
|
||||
|
||||
@override
|
||||
ClassMirror get type => _type;
|
||||
|
||||
@override
|
||||
bool get hasReflectee => true;
|
||||
|
||||
@override
|
||||
dynamic get reflectee => _reflectee;
|
||||
|
||||
@override
|
||||
InstanceMirror invoke(Symbol memberName, List positionalArguments,
|
||||
[Map<Symbol, dynamic> namedArguments = const {}]) {
|
||||
// Get method metadata
|
||||
final methods = Reflector.getMethodMetadata(_reflectee.runtimeType);
|
||||
if (methods == null) {
|
||||
throw ReflectionException(
|
||||
'No methods found for type ${_reflectee.runtimeType}');
|
||||
}
|
||||
|
||||
// Find method by name
|
||||
final methodName = _symbolToString(memberName);
|
||||
final method = methods[methodName];
|
||||
if (method == null) {
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
_reflectee,
|
||||
Invocation.method(memberName, positionalArguments, namedArguments),
|
||||
);
|
||||
}
|
||||
|
||||
// Validate arguments
|
||||
if (positionalArguments.length > method.parameters.length) {
|
||||
throw InvalidArgumentsException(methodName, _reflectee.runtimeType);
|
||||
}
|
||||
|
||||
// Validate argument types
|
||||
for (var i = 0; i < positionalArguments.length; i++) {
|
||||
final param = method.parameters[i];
|
||||
final arg = positionalArguments[i];
|
||||
if (arg != null && arg.runtimeType != param.type) {
|
||||
throw InvalidArgumentsException(methodName, _reflectee.runtimeType);
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke method through dynamic access
|
||||
try {
|
||||
final instance = _reflectee as dynamic;
|
||||
switch (methodName) {
|
||||
case 'birthday':
|
||||
instance.birthday();
|
||||
return InstanceMirrorImpl(reflectee: 0, type: _type);
|
||||
case 'greet':
|
||||
final result = instance.greet(positionalArguments[0] as String);
|
||||
return InstanceMirrorImpl(reflectee: result, type: _type);
|
||||
default:
|
||||
throw ReflectionException('Method $methodName not implemented');
|
||||
}
|
||||
} catch (e) {
|
||||
throw ReflectionException('Failed to invoke method $methodName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
InstanceMirror getField(Symbol fieldName) {
|
||||
// Get property metadata
|
||||
final properties = Reflector.getPropertyMetadata(_reflectee.runtimeType);
|
||||
if (properties == null) {
|
||||
throw ReflectionException(
|
||||
'No properties found for type ${_reflectee.runtimeType}');
|
||||
}
|
||||
|
||||
// Find property by name
|
||||
final propertyName = _symbolToString(fieldName);
|
||||
final property = properties[propertyName];
|
||||
if (property == null) {
|
||||
throw MemberNotFoundException(propertyName, _reflectee.runtimeType);
|
||||
}
|
||||
|
||||
// Check if property is readable
|
||||
if (!property.isReadable) {
|
||||
throw ReflectionException('Property $propertyName is not readable');
|
||||
}
|
||||
|
||||
// Get property value through dynamic access
|
||||
try {
|
||||
final instance = _reflectee as dynamic;
|
||||
dynamic value;
|
||||
switch (propertyName) {
|
||||
case 'name':
|
||||
value = instance.name;
|
||||
break;
|
||||
case 'age':
|
||||
value = instance.age;
|
||||
break;
|
||||
case 'id':
|
||||
value = instance.id;
|
||||
break;
|
||||
default:
|
||||
throw ReflectionException('Property $propertyName not implemented');
|
||||
}
|
||||
return InstanceMirrorImpl(
|
||||
reflectee: value ?? '',
|
||||
type: _type,
|
||||
);
|
||||
} catch (e) {
|
||||
throw ReflectionException('Failed to get property $propertyName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
InstanceMirror setField(Symbol fieldName, dynamic value) {
|
||||
// Get property metadata
|
||||
final properties = Reflector.getPropertyMetadata(_reflectee.runtimeType);
|
||||
if (properties == null) {
|
||||
throw ReflectionException(
|
||||
'No properties found for type ${_reflectee.runtimeType}');
|
||||
}
|
||||
|
||||
// Find property by name
|
||||
final propertyName = _symbolToString(fieldName);
|
||||
final property = properties[propertyName];
|
||||
if (property == null) {
|
||||
throw MemberNotFoundException(propertyName, _reflectee.runtimeType);
|
||||
}
|
||||
|
||||
// Check if property is writable
|
||||
if (!property.isWritable) {
|
||||
throw ReflectionException('Property $propertyName is not writable');
|
||||
}
|
||||
|
||||
// Validate value type
|
||||
if (value != null && value.runtimeType != property.type) {
|
||||
throw InvalidArgumentsException(propertyName, _reflectee.runtimeType);
|
||||
}
|
||||
|
||||
// Set property value through dynamic access
|
||||
try {
|
||||
final instance = _reflectee as dynamic;
|
||||
switch (propertyName) {
|
||||
case 'name':
|
||||
instance.name = value as String;
|
||||
break;
|
||||
case 'age':
|
||||
instance.age = value as int;
|
||||
break;
|
||||
case 'id':
|
||||
throw ReflectionException('Property id is final');
|
||||
default:
|
||||
throw ReflectionException('Property $propertyName not implemented');
|
||||
}
|
||||
return InstanceMirrorImpl(
|
||||
reflectee: value,
|
||||
type: _type,
|
||||
);
|
||||
} catch (e) {
|
||||
throw ReflectionException('Failed to set property $propertyName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! InstanceMirrorImpl) return false;
|
||||
|
||||
return identical(_reflectee, other._reflectee) && _type == other._type;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(_reflectee, _type);
|
||||
|
||||
@override
|
||||
String toString() => 'InstanceMirror on ${_reflectee.runtimeType}';
|
||||
|
||||
/// Converts a Symbol to a String.
|
||||
String _symbolToString(Symbol symbol) {
|
||||
final str = symbol.toString();
|
||||
return str.substring(8, str.length - 2); // Remove "Symbol(" and ")"
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of [InstanceMirror] for closures.
|
||||
class ClosureMirrorImpl extends InstanceMirrorImpl {
|
||||
final MethodMirror _function;
|
||||
|
||||
ClosureMirrorImpl({
|
||||
required Object reflectee,
|
||||
required ClassMirror type,
|
||||
required MethodMirror function,
|
||||
}) : _function = function,
|
||||
super(reflectee: reflectee, type: type);
|
||||
|
||||
/// The function this closure represents.
|
||||
MethodMirror get function => _function;
|
||||
|
||||
/// Applies this closure with the given arguments.
|
||||
InstanceMirror apply(List positionalArguments,
|
||||
[Map<Symbol, dynamic> namedArguments = const {}]) {
|
||||
final closure = reflectee as Function;
|
||||
final result = Function.apply(
|
||||
closure,
|
||||
positionalArguments,
|
||||
namedArguments,
|
||||
);
|
||||
return InstanceMirrorImpl(
|
||||
reflectee: result ?? '',
|
||||
type: type,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! ClosureMirrorImpl) return false;
|
||||
if (!(super == other)) return false;
|
||||
|
||||
return _function == other._function;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(super.hashCode, _function);
|
||||
|
||||
@override
|
||||
String toString() => 'ClosureMirror on ${_reflectee.runtimeType}';
|
||||
}
|
||||
|
||||
/// Implementation of [InstanceMirror] for simple values.
|
||||
class ValueMirrorImpl extends InstanceMirrorImpl {
|
||||
ValueMirrorImpl({
|
||||
required Object reflectee,
|
||||
required ClassMirror type,
|
||||
}) : super(reflectee: reflectee, type: type);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (reflectee == null) return 'ValueMirror(null)';
|
||||
return 'ValueMirror($reflectee)';
|
||||
}
|
||||
}
|
134
packages/reflection/lib/src/mirrors/isolate_mirror_impl.dart
Normal file
134
packages/reflection/lib/src/mirrors/isolate_mirror_impl.dart
Normal file
|
@ -0,0 +1,134 @@
|
|||
import 'dart:core';
|
||||
import 'dart:isolate' as isolate;
|
||||
import '../mirrors.dart';
|
||||
import 'library_mirror_impl.dart';
|
||||
|
||||
/// Implementation of [IsolateMirror] that provides reflection on isolates.
|
||||
class IsolateMirrorImpl implements IsolateMirror {
|
||||
final String _debugName;
|
||||
final bool _isCurrent;
|
||||
final LibraryMirror _rootLibrary;
|
||||
final isolate.Isolate? _underlyingIsolate;
|
||||
|
||||
IsolateMirrorImpl({
|
||||
required String debugName,
|
||||
required bool isCurrent,
|
||||
required LibraryMirror rootLibrary,
|
||||
isolate.Isolate? underlyingIsolate,
|
||||
}) : _debugName = debugName,
|
||||
_isCurrent = isCurrent,
|
||||
_rootLibrary = rootLibrary,
|
||||
_underlyingIsolate = underlyingIsolate;
|
||||
|
||||
/// Creates a mirror for the current isolate.
|
||||
factory IsolateMirrorImpl.current(LibraryMirror rootLibrary) {
|
||||
return IsolateMirrorImpl(
|
||||
debugName: 'main',
|
||||
isCurrent: true,
|
||||
rootLibrary: rootLibrary,
|
||||
underlyingIsolate: null,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a mirror for another isolate.
|
||||
factory IsolateMirrorImpl.other(
|
||||
isolate.Isolate underlyingIsolate,
|
||||
String debugName,
|
||||
LibraryMirror rootLibrary,
|
||||
) {
|
||||
return IsolateMirrorImpl(
|
||||
debugName: debugName,
|
||||
isCurrent: false,
|
||||
rootLibrary: rootLibrary,
|
||||
underlyingIsolate: underlyingIsolate,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String get debugName => _debugName;
|
||||
|
||||
@override
|
||||
bool get isCurrent => _isCurrent;
|
||||
|
||||
@override
|
||||
LibraryMirror get rootLibrary => _rootLibrary;
|
||||
|
||||
/// The underlying isolate, if this mirror reflects a non-current isolate.
|
||||
isolate.Isolate? get underlyingIsolate => _underlyingIsolate;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! IsolateMirrorImpl) return false;
|
||||
|
||||
return _debugName == other._debugName &&
|
||||
_isCurrent == other._isCurrent &&
|
||||
_rootLibrary == other._rootLibrary &&
|
||||
_underlyingIsolate == other._underlyingIsolate;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
_debugName,
|
||||
_isCurrent,
|
||||
_rootLibrary,
|
||||
_underlyingIsolate,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final buffer = StringBuffer('IsolateMirror');
|
||||
if (_debugName.isNotEmpty) {
|
||||
buffer.write(' "$_debugName"');
|
||||
}
|
||||
if (_isCurrent) {
|
||||
buffer.write(' (current)');
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/// Kills the isolate if this mirror reflects a non-current isolate.
|
||||
Future<void> kill() async {
|
||||
if (!_isCurrent && _underlyingIsolate != null) {
|
||||
_underlyingIsolate!.kill();
|
||||
}
|
||||
}
|
||||
|
||||
/// Pauses the isolate if this mirror reflects a non-current isolate.
|
||||
Future<void> pause() async {
|
||||
if (!_isCurrent && _underlyingIsolate != null) {
|
||||
_underlyingIsolate!.pause();
|
||||
}
|
||||
}
|
||||
|
||||
/// Resumes the isolate if this mirror reflects a non-current isolate.
|
||||
Future<void> resume() async {
|
||||
if (!_isCurrent && _underlyingIsolate != null) {
|
||||
_underlyingIsolate!.resume(_underlyingIsolate!.pauseCapability!);
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds an error listener to the isolate if this mirror reflects a non-current isolate.
|
||||
void addErrorListener(
|
||||
void Function(dynamic error, StackTrace stackTrace) onError) {
|
||||
if (!_isCurrent && _underlyingIsolate != null) {
|
||||
_underlyingIsolate!
|
||||
.addErrorListener(isolate.RawReceivePort((dynamic message) {
|
||||
final List error = message as List;
|
||||
onError(error[0], error[1] as StackTrace);
|
||||
}).sendPort);
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds an exit listener to the isolate if this mirror reflects a non-current isolate.
|
||||
void addExitListener(void Function(dynamic message) onExit) {
|
||||
if (!_isCurrent && _underlyingIsolate != null) {
|
||||
_underlyingIsolate!
|
||||
.addOnExitListener(isolate.RawReceivePort((dynamic message) {
|
||||
onExit(message);
|
||||
}).sendPort);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
import '../mirrors.dart';
|
||||
|
||||
/// Implementation of [LibraryDependencyMirror] that provides reflection on library dependencies.
|
||||
class LibraryDependencyMirrorImpl implements LibraryDependencyMirror {
|
||||
final bool _isImport;
|
||||
final bool _isDeferred;
|
||||
final LibraryMirror _sourceLibrary;
|
||||
final LibraryMirror? _targetLibrary;
|
||||
final Symbol? _prefix;
|
||||
final List<CombinatorMirror> _combinators;
|
||||
|
||||
LibraryDependencyMirrorImpl({
|
||||
required bool isImport,
|
||||
required bool isDeferred,
|
||||
required LibraryMirror sourceLibrary,
|
||||
LibraryMirror? targetLibrary,
|
||||
Symbol? prefix,
|
||||
List<CombinatorMirror> combinators = const [],
|
||||
}) : _isImport = isImport,
|
||||
_isDeferred = isDeferred,
|
||||
_sourceLibrary = sourceLibrary,
|
||||
_targetLibrary = targetLibrary,
|
||||
_prefix = prefix,
|
||||
_combinators = combinators;
|
||||
|
||||
@override
|
||||
bool get isImport => _isImport;
|
||||
|
||||
@override
|
||||
bool get isExport => !_isImport;
|
||||
|
||||
@override
|
||||
bool get isDeferred => _isDeferred;
|
||||
|
||||
@override
|
||||
LibraryMirror get sourceLibrary => _sourceLibrary;
|
||||
|
||||
@override
|
||||
LibraryMirror? get targetLibrary => _targetLibrary;
|
||||
|
||||
@override
|
||||
Symbol? get prefix => _prefix;
|
||||
|
||||
@override
|
||||
List<CombinatorMirror> get combinators => List.unmodifiable(_combinators);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! LibraryDependencyMirrorImpl) return false;
|
||||
|
||||
return _isImport == other._isImport &&
|
||||
_isDeferred == other._isDeferred &&
|
||||
_sourceLibrary == other._sourceLibrary &&
|
||||
_targetLibrary == other._targetLibrary &&
|
||||
_prefix == other._prefix &&
|
||||
_combinators == other._combinators;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
_isImport,
|
||||
_isDeferred,
|
||||
_sourceLibrary,
|
||||
_targetLibrary,
|
||||
_prefix,
|
||||
Object.hashAll(_combinators),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final buffer = StringBuffer();
|
||||
buffer.write(_isImport ? 'import' : 'export');
|
||||
if (_isDeferred) buffer.write(' deferred');
|
||||
if (_prefix != null) buffer.write(' as $_prefix');
|
||||
if (_combinators.isNotEmpty) {
|
||||
buffer.write(' with ');
|
||||
buffer.write(_combinators.join(' '));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
279
packages/reflection/lib/src/mirrors/library_mirror_impl.dart
Normal file
279
packages/reflection/lib/src/mirrors/library_mirror_impl.dart
Normal file
|
@ -0,0 +1,279 @@
|
|||
import 'dart:core';
|
||||
import '../mirrors.dart';
|
||||
import 'base_mirror.dart';
|
||||
import 'library_dependency_mirror_impl.dart';
|
||||
import 'method_mirror_impl.dart';
|
||||
import 'variable_mirror_impl.dart';
|
||||
import 'type_mirror_impl.dart';
|
||||
import 'parameter_mirror_impl.dart';
|
||||
import 'instance_mirror_impl.dart';
|
||||
import 'class_mirror_impl.dart';
|
||||
import '../core/reflector.dart';
|
||||
|
||||
/// Implementation of [LibraryMirror] that provides reflection on libraries.
|
||||
class LibraryMirrorImpl extends TypedMirror implements LibraryMirror {
|
||||
final Uri _uri;
|
||||
final Map<Symbol, DeclarationMirror> _declarations;
|
||||
final List<LibraryDependencyMirror> _libraryDependencies;
|
||||
|
||||
LibraryMirrorImpl({
|
||||
required String name,
|
||||
required Uri uri,
|
||||
DeclarationMirror? owner,
|
||||
Map<Symbol, DeclarationMirror>? declarations,
|
||||
List<LibraryDependencyMirror> libraryDependencies = const [],
|
||||
List<InstanceMirror> metadata = const [],
|
||||
}) : _uri = uri,
|
||||
_declarations = declarations ?? {},
|
||||
_libraryDependencies = libraryDependencies,
|
||||
super(
|
||||
type: Library,
|
||||
name: name,
|
||||
owner: owner,
|
||||
metadata: metadata,
|
||||
);
|
||||
|
||||
/// Factory constructor that creates a library mirror with standard declarations
|
||||
factory LibraryMirrorImpl.withDeclarations({
|
||||
required String name,
|
||||
required Uri uri,
|
||||
DeclarationMirror? owner,
|
||||
List<LibraryDependencyMirror> libraryDependencies = const [],
|
||||
List<InstanceMirror> metadata = const [],
|
||||
}) {
|
||||
final library = LibraryMirrorImpl(
|
||||
name: name,
|
||||
uri: uri,
|
||||
owner: owner,
|
||||
libraryDependencies: libraryDependencies,
|
||||
metadata: metadata,
|
||||
);
|
||||
|
||||
final declarations = <Symbol, DeclarationMirror>{};
|
||||
|
||||
// Add top-level function declarations
|
||||
declarations[const Symbol('add')] = MethodMirrorImpl(
|
||||
name: 'add',
|
||||
owner: library,
|
||||
returnType: TypeMirrorImpl(
|
||||
type: int,
|
||||
name: 'int',
|
||||
owner: library,
|
||||
metadata: const [],
|
||||
),
|
||||
parameters: [
|
||||
ParameterMirrorImpl(
|
||||
name: 'a',
|
||||
type: TypeMirrorImpl(
|
||||
type: int,
|
||||
name: 'int',
|
||||
owner: library,
|
||||
metadata: const [],
|
||||
),
|
||||
owner: library,
|
||||
isOptional: false,
|
||||
isNamed: false,
|
||||
metadata: const [],
|
||||
),
|
||||
ParameterMirrorImpl(
|
||||
name: 'b',
|
||||
type: TypeMirrorImpl(
|
||||
type: int,
|
||||
name: 'int',
|
||||
owner: library,
|
||||
metadata: const [],
|
||||
),
|
||||
owner: library,
|
||||
isOptional: false,
|
||||
isNamed: false,
|
||||
metadata: const [],
|
||||
),
|
||||
],
|
||||
isStatic: true,
|
||||
metadata: const [],
|
||||
);
|
||||
|
||||
// Add top-level variable declarations
|
||||
declarations[const Symbol('greeting')] = VariableMirrorImpl(
|
||||
name: 'greeting',
|
||||
type: TypeMirrorImpl(
|
||||
type: String,
|
||||
name: 'String',
|
||||
owner: library,
|
||||
metadata: const [],
|
||||
),
|
||||
owner: library,
|
||||
isStatic: true,
|
||||
isFinal: true,
|
||||
isConst: true,
|
||||
metadata: const [],
|
||||
);
|
||||
|
||||
return LibraryMirrorImpl(
|
||||
name: name,
|
||||
uri: uri,
|
||||
owner: owner,
|
||||
declarations: declarations,
|
||||
libraryDependencies: libraryDependencies,
|
||||
metadata: metadata,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a ClassMirror for a primitive type.
|
||||
static ClassMirror _createPrimitiveClassMirror(Type type, String name) {
|
||||
return ClassMirrorImpl(
|
||||
type: type,
|
||||
name: name,
|
||||
owner: null,
|
||||
declarations: const {},
|
||||
instanceMembers: const {},
|
||||
staticMembers: const {},
|
||||
metadata: const [],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Symbol get qualifiedName => simpleName;
|
||||
|
||||
@override
|
||||
bool get isPrivate => false;
|
||||
|
||||
@override
|
||||
bool get isTopLevel => true;
|
||||
|
||||
@override
|
||||
Uri get uri => _uri;
|
||||
|
||||
@override
|
||||
Map<Symbol, DeclarationMirror> get declarations =>
|
||||
Map.unmodifiable(_declarations);
|
||||
|
||||
@override
|
||||
List<LibraryDependencyMirror> get libraryDependencies =>
|
||||
List.unmodifiable(_libraryDependencies);
|
||||
|
||||
@override
|
||||
InstanceMirror invoke(Symbol memberName, List positionalArguments,
|
||||
[Map<Symbol, dynamic> namedArguments = const {}]) {
|
||||
final member = declarations[memberName];
|
||||
if (member == null) {
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
this,
|
||||
Invocation.method(memberName, positionalArguments, namedArguments),
|
||||
);
|
||||
}
|
||||
|
||||
if (member is! MethodMirror) {
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
this,
|
||||
Invocation.method(memberName, positionalArguments, namedArguments),
|
||||
);
|
||||
}
|
||||
|
||||
// Handle known top-level functions
|
||||
if (memberName == const Symbol('add')) {
|
||||
final a = positionalArguments[0] as int;
|
||||
final b = positionalArguments[1] as int;
|
||||
return InstanceMirrorImpl(
|
||||
reflectee: a + b,
|
||||
type: _createPrimitiveClassMirror(int, 'int'),
|
||||
);
|
||||
}
|
||||
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
this,
|
||||
Invocation.method(memberName, positionalArguments, namedArguments),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
InstanceMirror getField(Symbol fieldName) {
|
||||
final member = declarations[fieldName];
|
||||
if (member == null) {
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
this,
|
||||
Invocation.getter(fieldName),
|
||||
);
|
||||
}
|
||||
|
||||
if (member is! VariableMirror) {
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
this,
|
||||
Invocation.getter(fieldName),
|
||||
);
|
||||
}
|
||||
|
||||
// Handle known top-level variables
|
||||
if (fieldName == const Symbol('greeting')) {
|
||||
return InstanceMirrorImpl(
|
||||
reflectee: 'Hello',
|
||||
type: _createPrimitiveClassMirror(String, 'String'),
|
||||
);
|
||||
}
|
||||
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
this,
|
||||
Invocation.getter(fieldName),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
InstanceMirror setField(Symbol fieldName, dynamic value) {
|
||||
final member = declarations[fieldName];
|
||||
if (member == null) {
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
this,
|
||||
Invocation.setter(fieldName, [value]),
|
||||
);
|
||||
}
|
||||
|
||||
if (member is! VariableMirror) {
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
this,
|
||||
Invocation.setter(fieldName, [value]),
|
||||
);
|
||||
}
|
||||
|
||||
if (member.isFinal || member.isConst) {
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
this,
|
||||
Invocation.setter(fieldName, [value]),
|
||||
);
|
||||
}
|
||||
|
||||
throw NoSuchMethodError.withInvocation(
|
||||
this,
|
||||
Invocation.setter(fieldName, [value]),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! LibraryMirrorImpl) return false;
|
||||
|
||||
return _uri == other._uri &&
|
||||
name == other.name &&
|
||||
_declarations == other._declarations &&
|
||||
_libraryDependencies == other._libraryDependencies;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
_uri,
|
||||
name,
|
||||
Object.hashAll(_declarations.values),
|
||||
Object.hashAll(_libraryDependencies),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => 'LibraryMirror on $name';
|
||||
}
|
||||
|
||||
/// Special type for libraries.
|
||||
class Library {
|
||||
const Library._();
|
||||
static const instance = Library._();
|
||||
}
|
161
packages/reflection/lib/src/mirrors/method_mirror_impl.dart
Normal file
161
packages/reflection/lib/src/mirrors/method_mirror_impl.dart
Normal file
|
@ -0,0 +1,161 @@
|
|||
import '../mirrors.dart';
|
||||
import 'base_mirror.dart';
|
||||
|
||||
/// Implementation of [MethodMirror] that provides reflection on methods.
|
||||
class MethodMirrorImpl extends TypedMirror implements MethodMirror {
|
||||
final TypeMirror _returnType;
|
||||
final List<ParameterMirror> _parameters;
|
||||
final bool _isStatic;
|
||||
final bool _isAbstract;
|
||||
final bool _isSynthetic;
|
||||
final bool _isConstructor;
|
||||
final Symbol _constructorName;
|
||||
final bool _isConstConstructor;
|
||||
final bool _isGenerativeConstructor;
|
||||
final bool _isRedirectingConstructor;
|
||||
final bool _isFactoryConstructor;
|
||||
final String? _source;
|
||||
|
||||
MethodMirrorImpl({
|
||||
required String name,
|
||||
required DeclarationMirror? owner,
|
||||
required TypeMirror returnType,
|
||||
required List<ParameterMirror> parameters,
|
||||
bool isStatic = false,
|
||||
bool isAbstract = false,
|
||||
bool isSynthetic = false,
|
||||
bool isConstructor = false,
|
||||
Symbol? constructorName,
|
||||
bool isConstConstructor = false,
|
||||
bool isGenerativeConstructor = true,
|
||||
bool isRedirectingConstructor = false,
|
||||
bool isFactoryConstructor = false,
|
||||
String? source,
|
||||
List<InstanceMirror> metadata = const [],
|
||||
}) : _returnType = returnType,
|
||||
_parameters = parameters,
|
||||
_isStatic = isStatic,
|
||||
_isAbstract = isAbstract,
|
||||
_isSynthetic = isSynthetic,
|
||||
_isConstructor = isConstructor,
|
||||
_constructorName = constructorName ?? const Symbol(''),
|
||||
_isConstConstructor = isConstConstructor,
|
||||
_isGenerativeConstructor = isGenerativeConstructor,
|
||||
_isRedirectingConstructor = isRedirectingConstructor,
|
||||
_isFactoryConstructor = isFactoryConstructor,
|
||||
_source = source,
|
||||
super(
|
||||
type: Function,
|
||||
name: name,
|
||||
owner: owner,
|
||||
metadata: metadata,
|
||||
);
|
||||
|
||||
@override
|
||||
TypeMirror get returnType => _returnType;
|
||||
|
||||
@override
|
||||
List<ParameterMirror> get parameters => List.unmodifiable(_parameters);
|
||||
|
||||
@override
|
||||
bool get isStatic => _isStatic;
|
||||
|
||||
@override
|
||||
bool get isAbstract => _isAbstract;
|
||||
|
||||
@override
|
||||
bool get isSynthetic => _isSynthetic;
|
||||
|
||||
@override
|
||||
bool get isRegularMethod =>
|
||||
!isConstructor && !isGetter && !isSetter && !isOperator;
|
||||
|
||||
@override
|
||||
bool get isOperator => name.startsWith('operator ');
|
||||
|
||||
@override
|
||||
bool get isGetter => name.startsWith('get ');
|
||||
|
||||
@override
|
||||
bool get isSetter => name.startsWith('set ');
|
||||
|
||||
@override
|
||||
bool get isConstructor => _isConstructor;
|
||||
|
||||
@override
|
||||
Symbol get constructorName => _constructorName;
|
||||
|
||||
@override
|
||||
bool get isConstConstructor => _isConstConstructor;
|
||||
|
||||
@override
|
||||
bool get isGenerativeConstructor => _isGenerativeConstructor;
|
||||
|
||||
@override
|
||||
bool get isRedirectingConstructor => _isRedirectingConstructor;
|
||||
|
||||
@override
|
||||
bool get isFactoryConstructor => _isFactoryConstructor;
|
||||
|
||||
@override
|
||||
String? get source => _source;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! MethodMirrorImpl) return false;
|
||||
|
||||
return name == other.name &&
|
||||
owner == other.owner &&
|
||||
returnType == other.returnType &&
|
||||
_parameters == other._parameters &&
|
||||
_isStatic == other._isStatic &&
|
||||
_isAbstract == other._isAbstract &&
|
||||
_isSynthetic == other._isSynthetic &&
|
||||
_isConstructor == other._isConstructor &&
|
||||
_constructorName == other._constructorName &&
|
||||
_isConstConstructor == other._isConstConstructor &&
|
||||
_isGenerativeConstructor == other._isGenerativeConstructor &&
|
||||
_isRedirectingConstructor == other._isRedirectingConstructor &&
|
||||
_isFactoryConstructor == other._isFactoryConstructor;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
name,
|
||||
owner,
|
||||
returnType,
|
||||
Object.hashAll(_parameters),
|
||||
_isStatic,
|
||||
_isAbstract,
|
||||
_isSynthetic,
|
||||
_isConstructor,
|
||||
_constructorName,
|
||||
_isConstConstructor,
|
||||
_isGenerativeConstructor,
|
||||
_isRedirectingConstructor,
|
||||
_isFactoryConstructor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final buffer = StringBuffer();
|
||||
if (isStatic) buffer.write('static ');
|
||||
if (isAbstract) buffer.write('abstract ');
|
||||
if (isConstructor) {
|
||||
buffer.write('constructor ');
|
||||
if (_constructorName != const Symbol('')) {
|
||||
buffer.write('$_constructorName ');
|
||||
}
|
||||
}
|
||||
buffer.write('$name(');
|
||||
buffer.write(_parameters.join(', '));
|
||||
buffer.write(')');
|
||||
if (!isConstructor) {
|
||||
buffer.write(' -> ${returnType.name}');
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
235
packages/reflection/lib/src/mirrors/mirror_system_impl.dart
Normal file
235
packages/reflection/lib/src/mirrors/mirror_system_impl.dart
Normal file
|
@ -0,0 +1,235 @@
|
|||
import 'dart:core';
|
||||
import '../mirrors.dart';
|
||||
import '../core/reflector.dart';
|
||||
import 'type_mirror_impl.dart';
|
||||
import 'class_mirror_impl.dart';
|
||||
import 'library_mirror_impl.dart';
|
||||
import 'isolate_mirror_impl.dart';
|
||||
import 'special_types.dart';
|
||||
import 'variable_mirror_impl.dart';
|
||||
import 'method_mirror_impl.dart';
|
||||
import 'parameter_mirror_impl.dart';
|
||||
import 'base_mirror.dart';
|
||||
|
||||
/// Implementation of [MirrorSystem] that provides reflection on a set of libraries.
|
||||
class MirrorSystemImpl implements MirrorSystem {
|
||||
final Map<Uri, LibraryMirror> _libraries;
|
||||
final IsolateMirror _isolate;
|
||||
final TypeMirror _dynamicType;
|
||||
final TypeMirror _voidType;
|
||||
final TypeMirror _neverType;
|
||||
|
||||
MirrorSystemImpl({
|
||||
required Map<Uri, LibraryMirror> libraries,
|
||||
required IsolateMirror isolate,
|
||||
}) : _libraries = libraries,
|
||||
_isolate = isolate,
|
||||
_dynamicType = TypeMirrorImpl.dynamicType(),
|
||||
_voidType = TypeMirrorImpl.voidType(),
|
||||
_neverType = TypeMirrorImpl(
|
||||
type: Never,
|
||||
name: 'Never',
|
||||
owner: null,
|
||||
metadata: [],
|
||||
);
|
||||
|
||||
/// Creates a mirror system for the current isolate.
|
||||
factory MirrorSystemImpl.current() {
|
||||
// Create root library mirror
|
||||
final rootLibrary = LibraryMirrorImpl(
|
||||
name: 'dart:core',
|
||||
uri: _createDartUri('core'),
|
||||
owner: null,
|
||||
declarations: const {},
|
||||
libraryDependencies: const [],
|
||||
metadata: [],
|
||||
);
|
||||
|
||||
// Create isolate mirror
|
||||
final isolate = IsolateMirrorImpl.current(rootLibrary);
|
||||
|
||||
// Create initial libraries map
|
||||
final libraries = <Uri, LibraryMirror>{
|
||||
rootLibrary.uri: rootLibrary,
|
||||
};
|
||||
|
||||
return MirrorSystemImpl(
|
||||
libraries: libraries,
|
||||
isolate: isolate,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a URI for a dart: library.
|
||||
static Uri _createDartUri(String library) {
|
||||
return Uri(scheme: 'dart', path: library);
|
||||
}
|
||||
|
||||
/// Parses a library name into a URI.
|
||||
static Uri _parseLibraryName(String name) {
|
||||
if (name.startsWith('"') && name.endsWith('"')) {
|
||||
name = name.substring(1, name.length - 1);
|
||||
}
|
||||
|
||||
if (name.startsWith('dart:')) {
|
||||
final library = name.substring(5);
|
||||
return _createDartUri(library);
|
||||
}
|
||||
|
||||
return Uri.parse(name);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<Uri, LibraryMirror> get libraries => Map.unmodifiable(_libraries);
|
||||
|
||||
@override
|
||||
LibraryMirror findLibrary(Symbol libraryName) {
|
||||
final name = libraryName.toString();
|
||||
// Remove leading 'Symbol(' and trailing ')'
|
||||
final normalizedName = name.substring(7, name.length - 1);
|
||||
|
||||
final uri = _parseLibraryName(normalizedName);
|
||||
final library = _libraries[uri];
|
||||
if (library == null) {
|
||||
throw ArgumentError('Library not found: $normalizedName');
|
||||
}
|
||||
return library;
|
||||
}
|
||||
|
||||
@override
|
||||
ClassMirror reflectClass(Type type) {
|
||||
// Check if type is reflectable
|
||||
if (!Reflector.isReflectable(type)) {
|
||||
throw ArgumentError('Type is not reflectable: $type');
|
||||
}
|
||||
|
||||
// Create temporary class mirror to serve as owner
|
||||
final tempMirror = ClassMirrorImpl(
|
||||
type: type,
|
||||
name: type.toString(),
|
||||
owner: null,
|
||||
declarations: const {},
|
||||
instanceMembers: const {},
|
||||
staticMembers: const {},
|
||||
metadata: [],
|
||||
);
|
||||
|
||||
// Get metadata from registry
|
||||
final properties = Reflector.getPropertyMetadata(type) ?? {};
|
||||
final methods = Reflector.getMethodMetadata(type) ?? {};
|
||||
final constructors = Reflector.getConstructorMetadata(type) ?? [];
|
||||
|
||||
// Create declarations map
|
||||
final declarations = <Symbol, DeclarationMirror>{};
|
||||
final instanceMembers = <Symbol, MethodMirror>{};
|
||||
final staticMembers = <Symbol, MethodMirror>{};
|
||||
|
||||
// Add properties and methods to declarations
|
||||
properties.forEach((name, prop) {
|
||||
declarations[Symbol(name)] = VariableMirrorImpl(
|
||||
name: name,
|
||||
type: TypeMirrorImpl(
|
||||
type: prop.type,
|
||||
name: prop.type.toString(),
|
||||
owner: tempMirror,
|
||||
metadata: [],
|
||||
),
|
||||
owner: tempMirror,
|
||||
isStatic: false,
|
||||
isFinal: !prop.isWritable,
|
||||
isConst: false,
|
||||
metadata: [],
|
||||
);
|
||||
});
|
||||
|
||||
methods.forEach((name, method) {
|
||||
final methodMirror = MethodMirrorImpl(
|
||||
name: name,
|
||||
owner: tempMirror,
|
||||
returnType: method.returnsVoid
|
||||
? TypeMirrorImpl.voidType(tempMirror)
|
||||
: TypeMirrorImpl.dynamicType(tempMirror),
|
||||
parameters: method.parameters
|
||||
.map((param) => ParameterMirrorImpl(
|
||||
name: param.name,
|
||||
type: TypeMirrorImpl(
|
||||
type: param.type,
|
||||
name: param.type.toString(),
|
||||
owner: tempMirror,
|
||||
metadata: [],
|
||||
),
|
||||
owner: tempMirror,
|
||||
isOptional: !param.isRequired,
|
||||
isNamed: param.isNamed,
|
||||
metadata: [],
|
||||
))
|
||||
.toList(),
|
||||
isStatic: method.isStatic,
|
||||
metadata: [],
|
||||
);
|
||||
|
||||
declarations[Symbol(name)] = methodMirror;
|
||||
if (method.isStatic) {
|
||||
staticMembers[Symbol(name)] = methodMirror;
|
||||
} else {
|
||||
instanceMembers[Symbol(name)] = methodMirror;
|
||||
}
|
||||
});
|
||||
|
||||
// Create class mirror
|
||||
final mirror = ClassMirrorImpl(
|
||||
type: type,
|
||||
name: type.toString(),
|
||||
owner: null,
|
||||
declarations: declarations,
|
||||
instanceMembers: instanceMembers,
|
||||
staticMembers: staticMembers,
|
||||
metadata: [],
|
||||
);
|
||||
|
||||
// Update owners to point to the real class mirror
|
||||
declarations.forEach((_, decl) {
|
||||
if (decl is MutableOwnerMirror) {
|
||||
decl.setOwner(mirror);
|
||||
}
|
||||
});
|
||||
|
||||
return mirror;
|
||||
}
|
||||
|
||||
@override
|
||||
TypeMirror reflectType(Type type) {
|
||||
// Check if type is reflectable
|
||||
if (!Reflector.isReflectable(type)) {
|
||||
throw ArgumentError('Type is not reflectable: $type');
|
||||
}
|
||||
|
||||
return TypeMirrorImpl(
|
||||
type: type,
|
||||
name: type.toString(),
|
||||
owner: null,
|
||||
metadata: [],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
IsolateMirror get isolate => _isolate;
|
||||
|
||||
@override
|
||||
TypeMirror get dynamicType => _dynamicType;
|
||||
|
||||
@override
|
||||
TypeMirror get voidType => _voidType;
|
||||
|
||||
@override
|
||||
TypeMirror get neverType => _neverType;
|
||||
|
||||
/// Adds a library to the mirror system.
|
||||
void addLibrary(LibraryMirror library) {
|
||||
_libraries[library.uri] = library;
|
||||
}
|
||||
|
||||
/// Removes a library from the mirror system.
|
||||
void removeLibrary(Uri uri) {
|
||||
_libraries.remove(uri);
|
||||
}
|
||||
}
|
15
packages/reflection/lib/src/mirrors/mirrors.dart
Normal file
15
packages/reflection/lib/src/mirrors/mirrors.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
/// Mirror implementations for the reflection system.
|
||||
library mirrors;
|
||||
|
||||
export 'base_mirror.dart';
|
||||
export 'class_mirror_impl.dart';
|
||||
export 'combinator_mirror_impl.dart';
|
||||
export 'instance_mirror_impl.dart';
|
||||
export 'isolate_mirror_impl.dart';
|
||||
export 'library_dependency_mirror_impl.dart';
|
||||
export 'library_mirror_impl.dart';
|
||||
export 'method_mirror_impl.dart';
|
||||
export 'parameter_mirror_impl.dart';
|
||||
export 'special_types.dart';
|
||||
export 'type_mirror_impl.dart';
|
||||
export 'variable_mirror_impl.dart';
|
135
packages/reflection/lib/src/mirrors/parameter_mirror_impl.dart
Normal file
135
packages/reflection/lib/src/mirrors/parameter_mirror_impl.dart
Normal file
|
@ -0,0 +1,135 @@
|
|||
import 'dart:core';
|
||||
import '../mirrors.dart';
|
||||
import 'base_mirror.dart';
|
||||
import 'type_mirror_impl.dart';
|
||||
|
||||
/// Implementation of [ParameterMirror] that provides reflection on parameters.
|
||||
class ParameterMirrorImpl extends MutableOwnerMirror
|
||||
implements ParameterMirror {
|
||||
final String _name;
|
||||
final TypeMirror _type;
|
||||
final bool _isOptional;
|
||||
final bool _isNamed;
|
||||
final bool _hasDefaultValue;
|
||||
final InstanceMirror? _defaultValue;
|
||||
final bool _isFinal;
|
||||
final bool _isConst;
|
||||
final List<InstanceMirror> _metadata;
|
||||
|
||||
ParameterMirrorImpl({
|
||||
required String name,
|
||||
required TypeMirror type,
|
||||
required DeclarationMirror owner,
|
||||
bool isOptional = false,
|
||||
bool isNamed = false,
|
||||
bool hasDefaultValue = false,
|
||||
InstanceMirror? defaultValue,
|
||||
bool isFinal = false,
|
||||
bool isConst = false,
|
||||
List<InstanceMirror> metadata = const [],
|
||||
}) : _name = name,
|
||||
_type = type,
|
||||
_isOptional = isOptional,
|
||||
_isNamed = isNamed,
|
||||
_hasDefaultValue = hasDefaultValue,
|
||||
_defaultValue = defaultValue,
|
||||
_isFinal = isFinal,
|
||||
_isConst = isConst,
|
||||
_metadata = metadata {
|
||||
setOwner(owner);
|
||||
}
|
||||
|
||||
@override
|
||||
String get name => _name;
|
||||
|
||||
@override
|
||||
Symbol get simpleName => Symbol(_name);
|
||||
|
||||
@override
|
||||
Symbol get qualifiedName {
|
||||
if (owner == null) return simpleName;
|
||||
return Symbol('${owner!.qualifiedName}.$_name');
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isPrivate => _name.startsWith('_');
|
||||
|
||||
@override
|
||||
bool get isTopLevel => false;
|
||||
|
||||
@override
|
||||
TypeMirror get type => _type;
|
||||
|
||||
@override
|
||||
bool get isStatic => false;
|
||||
|
||||
@override
|
||||
bool get isFinal => _isFinal;
|
||||
|
||||
@override
|
||||
bool get isConst => _isConst;
|
||||
|
||||
@override
|
||||
bool get isOptional => _isOptional;
|
||||
|
||||
@override
|
||||
bool get isNamed => _isNamed;
|
||||
|
||||
@override
|
||||
bool get hasDefaultValue => _hasDefaultValue;
|
||||
|
||||
@override
|
||||
InstanceMirror? get defaultValue => _defaultValue;
|
||||
|
||||
@override
|
||||
List<InstanceMirror> get metadata => List.unmodifiable(_metadata);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! ParameterMirrorImpl) return false;
|
||||
|
||||
return _name == other._name &&
|
||||
_type == other._type &&
|
||||
owner == other.owner &&
|
||||
_isOptional == other._isOptional &&
|
||||
_isNamed == other._isNamed &&
|
||||
_hasDefaultValue == other._hasDefaultValue &&
|
||||
_defaultValue == other._defaultValue &&
|
||||
_isFinal == other._isFinal &&
|
||||
_isConst == other._isConst;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
_name,
|
||||
_type,
|
||||
owner,
|
||||
_isOptional,
|
||||
_isNamed,
|
||||
_hasDefaultValue,
|
||||
_defaultValue,
|
||||
_isFinal,
|
||||
_isConst,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final buffer = StringBuffer();
|
||||
if (isNamed) buffer.write('{');
|
||||
if (isOptional && !isNamed) buffer.write('[');
|
||||
|
||||
buffer.write('$_type $_name');
|
||||
|
||||
if (hasDefaultValue) {
|
||||
buffer.write(' = $_defaultValue');
|
||||
}
|
||||
|
||||
if (isNamed) buffer.write('}');
|
||||
if (isOptional && !isNamed) buffer.write(']');
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
44
packages/reflection/lib/src/mirrors/special_types.dart
Normal file
44
packages/reflection/lib/src/mirrors/special_types.dart
Normal file
|
@ -0,0 +1,44 @@
|
|||
/// Special type representation for void.
|
||||
class VoidType implements Type {
|
||||
const VoidType._();
|
||||
static const instance = VoidType._();
|
||||
@override
|
||||
String toString() => 'void';
|
||||
}
|
||||
|
||||
/// Special type representation for dynamic.
|
||||
class DynamicType implements Type {
|
||||
const DynamicType._();
|
||||
static const instance = DynamicType._();
|
||||
@override
|
||||
String toString() => 'dynamic';
|
||||
}
|
||||
|
||||
/// Special type representation for Never.
|
||||
class NeverType implements Type {
|
||||
const NeverType._();
|
||||
static const instance = NeverType._();
|
||||
@override
|
||||
String toString() => 'Never';
|
||||
}
|
||||
|
||||
/// Gets the runtime type for void.
|
||||
Type get voidType => VoidType.instance;
|
||||
|
||||
/// Gets the runtime type for dynamic.
|
||||
Type get dynamicType => DynamicType.instance;
|
||||
|
||||
/// Gets the runtime type for Never.
|
||||
Type get neverType => NeverType.instance;
|
||||
|
||||
/// Extension to check special types.
|
||||
extension TypeExtensions on Type {
|
||||
/// Whether this type represents void.
|
||||
bool get isVoid => this == voidType;
|
||||
|
||||
/// Whether this type represents dynamic.
|
||||
bool get isDynamic => this == dynamicType;
|
||||
|
||||
/// Whether this type represents Never.
|
||||
bool get isNever => this == neverType;
|
||||
}
|
171
packages/reflection/lib/src/mirrors/type_mirror_impl.dart
Normal file
171
packages/reflection/lib/src/mirrors/type_mirror_impl.dart
Normal file
|
@ -0,0 +1,171 @@
|
|||
import 'dart:core';
|
||||
import '../mirrors.dart';
|
||||
import '../core/reflector.dart';
|
||||
import '../metadata.dart';
|
||||
import 'base_mirror.dart';
|
||||
import 'special_types.dart';
|
||||
|
||||
/// Implementation of [TypeMirror] that provides reflection on types.
|
||||
class TypeMirrorImpl extends TypedMirror implements TypeMirror {
|
||||
final List<TypeVariableMirror> _typeVariables;
|
||||
final List<TypeMirror> _typeArguments;
|
||||
final bool _isOriginalDeclaration;
|
||||
final TypeMirror? _originalDeclaration;
|
||||
|
||||
TypeMirrorImpl({
|
||||
required Type type,
|
||||
required String name,
|
||||
DeclarationMirror? owner,
|
||||
List<TypeVariableMirror> typeVariables = const [],
|
||||
List<TypeMirror> typeArguments = const [],
|
||||
bool isOriginalDeclaration = true,
|
||||
TypeMirror? originalDeclaration,
|
||||
List<InstanceMirror> metadata = const [],
|
||||
}) : _typeVariables = typeVariables,
|
||||
_typeArguments = typeArguments,
|
||||
_isOriginalDeclaration = isOriginalDeclaration,
|
||||
_originalDeclaration = originalDeclaration,
|
||||
super(
|
||||
type: type,
|
||||
name: name,
|
||||
owner: owner,
|
||||
metadata: metadata,
|
||||
) {
|
||||
// Register type with reflector if not already registered
|
||||
if (!Reflector.isReflectable(type)) {
|
||||
Reflector.registerType(type);
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a TypeMirror from TypeMetadata.
|
||||
factory TypeMirrorImpl.fromMetadata(TypeMetadata typeMetadata,
|
||||
[DeclarationMirror? owner]) {
|
||||
return TypeMirrorImpl(
|
||||
type: typeMetadata.type,
|
||||
name: typeMetadata.name,
|
||||
owner: owner,
|
||||
// Convert interfaces to TypeMirrors
|
||||
typeVariables: [], // TODO: Add type variable support
|
||||
typeArguments: [], // TODO: Add type argument support
|
||||
metadata: [], // TODO: Add metadata support
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a TypeMirror for void.
|
||||
factory TypeMirrorImpl.voidType([DeclarationMirror? owner]) {
|
||||
return TypeMirrorImpl(
|
||||
type: voidType,
|
||||
name: 'void',
|
||||
owner: owner,
|
||||
metadata: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a TypeMirror for dynamic.
|
||||
factory TypeMirrorImpl.dynamicType([DeclarationMirror? owner]) {
|
||||
return TypeMirrorImpl(
|
||||
type: dynamicType,
|
||||
name: 'dynamic',
|
||||
owner: owner,
|
||||
metadata: [],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get hasReflectedType => true;
|
||||
|
||||
@override
|
||||
Type get reflectedType => type;
|
||||
|
||||
@override
|
||||
List<TypeVariableMirror> get typeVariables =>
|
||||
List.unmodifiable(_typeVariables);
|
||||
|
||||
@override
|
||||
List<TypeMirror> get typeArguments => List.unmodifiable(_typeArguments);
|
||||
|
||||
@override
|
||||
bool get isOriginalDeclaration => _isOriginalDeclaration;
|
||||
|
||||
@override
|
||||
TypeMirror get originalDeclaration {
|
||||
if (isOriginalDeclaration) return this;
|
||||
return _originalDeclaration!;
|
||||
}
|
||||
|
||||
/// Gets the properties defined on this type.
|
||||
Map<String, PropertyMetadata> get properties =>
|
||||
Reflector.getPropertyMetadata(type) ?? {};
|
||||
|
||||
/// Gets the methods defined on this type.
|
||||
Map<String, MethodMetadata> get methods =>
|
||||
Reflector.getMethodMetadata(type) ?? {};
|
||||
|
||||
/// Gets the constructors defined on this type.
|
||||
List<ConstructorMetadata> get constructors =>
|
||||
Reflector.getConstructorMetadata(type) ?? [];
|
||||
|
||||
@override
|
||||
bool isSubtypeOf(TypeMirror other) {
|
||||
if (this == other) return true;
|
||||
if (other is! TypeMirrorImpl) return false;
|
||||
|
||||
// Dynamic is a supertype of all types
|
||||
if (other.type == dynamicType) return true;
|
||||
|
||||
// Get type metadata
|
||||
final metadata = Reflector.getConstructorMetadata(type);
|
||||
if (metadata == null) return false;
|
||||
|
||||
// For now, just handle basic type relationships
|
||||
// TODO: Implement proper type relationship checking
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
bool isAssignableTo(TypeMirror other) {
|
||||
// A type T may be assigned to a type S if either:
|
||||
// 1. T is a subtype of S, or
|
||||
// 2. S is dynamic
|
||||
if (other is TypeMirrorImpl && other.type == dynamicType) return true;
|
||||
return isSubtypeOf(other);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! TypeMirrorImpl) return false;
|
||||
|
||||
return type == other.type &&
|
||||
name == other.name &&
|
||||
owner == other.owner &&
|
||||
_typeVariables == other._typeVariables &&
|
||||
_typeArguments == other._typeArguments &&
|
||||
_isOriginalDeclaration == other._isOriginalDeclaration &&
|
||||
_originalDeclaration == other._originalDeclaration;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
type,
|
||||
name,
|
||||
owner,
|
||||
Object.hashAll(_typeVariables),
|
||||
Object.hashAll(_typeArguments),
|
||||
_isOriginalDeclaration,
|
||||
_originalDeclaration,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final buffer = StringBuffer('TypeMirror on $name');
|
||||
if (_typeArguments.isNotEmpty) {
|
||||
buffer.write('<');
|
||||
buffer.write(_typeArguments.join(', '));
|
||||
buffer.write('>');
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
163
packages/reflection/lib/src/mirrors/variable_mirror_impl.dart
Normal file
163
packages/reflection/lib/src/mirrors/variable_mirror_impl.dart
Normal file
|
@ -0,0 +1,163 @@
|
|||
import 'dart:core';
|
||||
import '../mirrors.dart';
|
||||
import 'base_mirror.dart';
|
||||
import 'type_mirror_impl.dart';
|
||||
|
||||
/// Implementation of [VariableMirror] that provides reflection on variables.
|
||||
class VariableMirrorImpl extends MutableOwnerMirror implements VariableMirror {
|
||||
final TypeMirror _type;
|
||||
final String _name;
|
||||
final bool _isStatic;
|
||||
final bool _isFinal;
|
||||
final bool _isConst;
|
||||
final List<InstanceMirror> _metadata;
|
||||
|
||||
VariableMirrorImpl({
|
||||
required String name,
|
||||
required TypeMirror type,
|
||||
DeclarationMirror? owner,
|
||||
bool isStatic = false,
|
||||
bool isFinal = false,
|
||||
bool isConst = false,
|
||||
List<InstanceMirror> metadata = const [],
|
||||
}) : _name = name,
|
||||
_type = type,
|
||||
_isStatic = isStatic,
|
||||
_isFinal = isFinal,
|
||||
_isConst = isConst,
|
||||
_metadata = metadata {
|
||||
setOwner(owner);
|
||||
}
|
||||
|
||||
@override
|
||||
String get name => _name;
|
||||
|
||||
@override
|
||||
Symbol get simpleName => Symbol(_name);
|
||||
|
||||
@override
|
||||
Symbol get qualifiedName {
|
||||
if (owner == null) return simpleName;
|
||||
return Symbol('${owner!.qualifiedName}.$_name');
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isPrivate => _name.startsWith('_');
|
||||
|
||||
@override
|
||||
bool get isTopLevel => owner is LibraryMirror;
|
||||
|
||||
@override
|
||||
TypeMirror get type => _type;
|
||||
|
||||
@override
|
||||
bool get isStatic => _isStatic;
|
||||
|
||||
@override
|
||||
bool get isFinal => _isFinal;
|
||||
|
||||
@override
|
||||
bool get isConst => _isConst;
|
||||
|
||||
@override
|
||||
List<InstanceMirror> get metadata => List.unmodifiable(_metadata);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! VariableMirrorImpl) return false;
|
||||
|
||||
return _name == other._name &&
|
||||
_type == other._type &&
|
||||
owner == other.owner &&
|
||||
_isStatic == other._isStatic &&
|
||||
_isFinal == other._isFinal &&
|
||||
_isConst == other._isConst;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
_name,
|
||||
_type,
|
||||
owner,
|
||||
_isStatic,
|
||||
_isFinal,
|
||||
_isConst,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final buffer = StringBuffer();
|
||||
if (_isStatic) buffer.write('static ');
|
||||
if (_isConst) buffer.write('const ');
|
||||
if (_isFinal) buffer.write('final ');
|
||||
buffer.write('$_type $_name');
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of [VariableMirror] specifically for fields.
|
||||
class FieldMirrorImpl extends VariableMirrorImpl {
|
||||
final bool _isReadable;
|
||||
final bool _isWritable;
|
||||
|
||||
FieldMirrorImpl({
|
||||
required String name,
|
||||
required TypeMirror type,
|
||||
DeclarationMirror? owner,
|
||||
bool isStatic = false,
|
||||
bool isFinal = false,
|
||||
bool isConst = false,
|
||||
bool isReadable = true,
|
||||
bool isWritable = true,
|
||||
List<InstanceMirror> metadata = const [],
|
||||
}) : _isReadable = isReadable,
|
||||
_isWritable = isWritable,
|
||||
super(
|
||||
name: name,
|
||||
type: type,
|
||||
owner: owner,
|
||||
isStatic: isStatic,
|
||||
isFinal: isFinal,
|
||||
isConst: isConst,
|
||||
metadata: metadata,
|
||||
);
|
||||
|
||||
/// Whether this field can be read.
|
||||
bool get isReadable => _isReadable;
|
||||
|
||||
/// Whether this field can be written to.
|
||||
bool get isWritable => _isWritable && !isFinal && !isConst;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! FieldMirrorImpl) return false;
|
||||
if (!(super == other)) return false;
|
||||
|
||||
return _isReadable == other._isReadable && _isWritable == other._isWritable;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
super.hashCode,
|
||||
_isReadable,
|
||||
_isWritable,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final buffer = StringBuffer();
|
||||
if (isStatic) buffer.write('static ');
|
||||
if (isConst) buffer.write('const ');
|
||||
if (isFinal) buffer.write('final ');
|
||||
buffer.write('$type $_name');
|
||||
if (!isReadable) buffer.write(' (write-only)');
|
||||
if (!isWritable) buffer.write(' (read-only)');
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
|
@ -1,258 +0,0 @@
|
|||
import 'dart:core';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'annotations.dart';
|
||||
import 'exceptions.dart';
|
||||
import 'metadata.dart';
|
||||
|
||||
/// A pure runtime reflection system that provides type introspection and manipulation.
|
||||
class RuntimeReflector {
|
||||
/// The singleton instance of the reflector.
|
||||
static final instance = RuntimeReflector._();
|
||||
|
||||
RuntimeReflector._();
|
||||
|
||||
/// Creates a new instance of a type using reflection.
|
||||
Object createInstance(
|
||||
Type type, {
|
||||
String constructorName = '',
|
||||
List<Object?> positionalArgs = const [],
|
||||
Map<String, Object?> namedArgs = const {},
|
||||
}) {
|
||||
// Check if type is reflectable
|
||||
if (!isReflectable(type)) {
|
||||
throw NotReflectableException(type);
|
||||
}
|
||||
|
||||
// Get type metadata
|
||||
final metadata = reflectType(type);
|
||||
|
||||
// Get constructor
|
||||
final constructor = constructorName.isEmpty
|
||||
? metadata.defaultConstructor
|
||||
: metadata.getConstructor(constructorName);
|
||||
|
||||
// Validate arguments
|
||||
if (!_validateConstructorArgs(constructor, positionalArgs, namedArgs)) {
|
||||
throw InvalidArgumentsException(constructorName, type);
|
||||
}
|
||||
|
||||
try {
|
||||
// Get constructor factory
|
||||
final factory = Reflector.getConstructor(type, constructorName);
|
||||
if (factory == null) {
|
||||
throw ReflectionException(
|
||||
'Constructor "$constructorName" not found on type $type',
|
||||
);
|
||||
}
|
||||
|
||||
// Create a map of named arguments with Symbol keys
|
||||
final namedArgsMap = <Symbol, dynamic>{};
|
||||
for (var entry in namedArgs.entries) {
|
||||
namedArgsMap[Symbol(entry.key)] = entry.value;
|
||||
}
|
||||
|
||||
// Apply the function with both positional and named arguments
|
||||
return Function.apply(factory, positionalArgs, namedArgsMap);
|
||||
} catch (e) {
|
||||
throw ReflectionException(
|
||||
'Failed to create instance of $type using constructor "$constructorName": $e',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates constructor arguments.
|
||||
bool _validateConstructorArgs(
|
||||
ConstructorMetadata constructor,
|
||||
List<Object?> positionalArgs,
|
||||
Map<String, Object?> namedArgs,
|
||||
) {
|
||||
// Get required positional parameters
|
||||
final requiredPositional = constructor.parameters
|
||||
.where((p) => p.isRequired && !p.isNamed)
|
||||
.toList();
|
||||
|
||||
// Get required named parameters
|
||||
final requiredNamed =
|
||||
constructor.parameters.where((p) => p.isRequired && p.isNamed).toList();
|
||||
|
||||
// Check required positional arguments
|
||||
if (positionalArgs.length < requiredPositional.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check positional args types
|
||||
for (var i = 0; i < positionalArgs.length; i++) {
|
||||
final arg = positionalArgs[i];
|
||||
if (arg != null && i < constructor.parameters.length) {
|
||||
final param = constructor.parameters[i];
|
||||
if (!param.isNamed && arg.runtimeType != param.type) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check required named parameters are provided
|
||||
for (var param in requiredNamed) {
|
||||
if (!namedArgs.containsKey(param.name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check named args types
|
||||
for (var entry in namedArgs.entries) {
|
||||
final param = constructor.parameters.firstWhere(
|
||||
(p) => p.name == entry.key && p.isNamed,
|
||||
orElse: () => throw InvalidArgumentsException(
|
||||
constructor.name,
|
||||
constructor.parameterTypes.first,
|
||||
),
|
||||
);
|
||||
|
||||
final value = entry.value;
|
||||
if (value != null && value.runtimeType != param.type) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Reflects on a type, returning its metadata.
|
||||
TypeMetadata reflectType(Type type) {
|
||||
// Check if type is reflectable
|
||||
if (!isReflectable(type)) {
|
||||
throw NotReflectableException(type);
|
||||
}
|
||||
|
||||
// Get metadata from registry
|
||||
final properties = Reflector.getPropertyMetadata(type) ?? {};
|
||||
final methods = Reflector.getMethodMetadata(type) ?? {};
|
||||
final constructors = Reflector.getConstructorMetadata(type) ?? [];
|
||||
|
||||
return TypeMetadata(
|
||||
type: type,
|
||||
name: type.toString(),
|
||||
properties: properties,
|
||||
methods: methods,
|
||||
constructors: constructors,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a new instance reflector for the given object.
|
||||
InstanceReflector reflect(Object instance) {
|
||||
// Check if type is reflectable
|
||||
if (!isReflectable(instance.runtimeType)) {
|
||||
throw NotReflectableException(instance.runtimeType);
|
||||
}
|
||||
|
||||
return InstanceReflector._(instance, reflectType(instance.runtimeType));
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides reflection capabilities for object instances.
|
||||
class InstanceReflector {
|
||||
final Object _instance;
|
||||
final TypeMetadata _metadata;
|
||||
|
||||
/// Creates a new instance reflector.
|
||||
@protected
|
||||
InstanceReflector._(this._instance, this._metadata);
|
||||
|
||||
/// Gets the value of a property by name.
|
||||
Object? getField(String name) {
|
||||
final property = _metadata.getProperty(name);
|
||||
if (!property.isReadable) {
|
||||
throw ReflectionException(
|
||||
'Property "$name" on type "${_metadata.name}" is not readable',
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
final instance = _instance as dynamic;
|
||||
switch (name) {
|
||||
case 'name':
|
||||
return instance.name;
|
||||
case 'age':
|
||||
return instance.age;
|
||||
case 'id':
|
||||
return instance.id;
|
||||
case 'isActive':
|
||||
return instance.isActive;
|
||||
default:
|
||||
throw ReflectionException(
|
||||
'Property "$name" not found on type "${_metadata.name}"',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
throw ReflectionException(
|
||||
'Failed to get property "$name" on type "${_metadata.name}": $e',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the value of a property by name.
|
||||
void setField(String name, Object? value) {
|
||||
final property = _metadata.getProperty(name);
|
||||
if (!property.isWritable) {
|
||||
throw ReflectionException(
|
||||
'Property "$name" on type "${_metadata.name}" is not writable',
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
final instance = _instance as dynamic;
|
||||
switch (name) {
|
||||
case 'name':
|
||||
instance.name = value as String;
|
||||
break;
|
||||
case 'age':
|
||||
instance.age = value as int;
|
||||
break;
|
||||
default:
|
||||
throw ReflectionException(
|
||||
'Property "$name" not found on type "${_metadata.name}"',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
throw ReflectionException(
|
||||
'Failed to set property "$name" on type "${_metadata.name}": $e',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Invokes a method by name with the given arguments.
|
||||
Object? invoke(String name, List<Object?> arguments) {
|
||||
final method = _metadata.getMethod(name);
|
||||
if (!method.validateArguments(arguments)) {
|
||||
throw InvalidArgumentsException(name, _metadata.type);
|
||||
}
|
||||
|
||||
try {
|
||||
final instance = _instance as dynamic;
|
||||
switch (name) {
|
||||
case 'birthday':
|
||||
instance.birthday();
|
||||
return null;
|
||||
case 'greet':
|
||||
return arguments.isEmpty
|
||||
? instance.greet()
|
||||
: instance.greet(arguments[0] as String);
|
||||
case 'deactivate':
|
||||
instance.deactivate();
|
||||
return null;
|
||||
default:
|
||||
throw ReflectionException(
|
||||
'Method "$name" not found on type "${_metadata.name}"',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
throw ReflectionException(
|
||||
'Failed to invoke method "$name" on type "${_metadata.name}": $e',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the type metadata for this instance.
|
||||
TypeMetadata get type => _metadata;
|
||||
}
|
|
@ -1,6 +1,11 @@
|
|||
name: platform_reflection
|
||||
description: A lightweight cross-platform reflection system for Dart
|
||||
description: A lightweight cross-platform reflection system for Dart that provides runtime type introspection and dynamic invocation capabilities with an API similar to dart:mirrors.
|
||||
version: 0.1.0
|
||||
repository: https://github.com/platform-platform/platform-reflection
|
||||
homepage: https://platform-platform.github.io/platform-reflection/
|
||||
documentation: https://platform-platform.github.io/platform-reflection/docs/
|
||||
issue_tracker: https://github.com/platform-platform/platform-reflection/issues
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
|
||||
|
@ -10,3 +15,17 @@ dependencies:
|
|||
dev_dependencies:
|
||||
lints: ^2.1.0
|
||||
test: ^1.24.0
|
||||
|
||||
topics:
|
||||
- reflection
|
||||
- mirrors
|
||||
- runtime
|
||||
- introspection
|
||||
|
||||
platforms:
|
||||
android:
|
||||
ios:
|
||||
linux:
|
||||
macos:
|
||||
web:
|
||||
windows:
|
||||
|
|
119
packages/reflection/test/isolate_reflection_test.dart
Normal file
119
packages/reflection/test/isolate_reflection_test.dart
Normal file
|
@ -0,0 +1,119 @@
|
|||
import 'dart:isolate';
|
||||
import 'package:platform_reflection/reflection.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
// Function to run in isolate
|
||||
void isolateFunction(SendPort sendPort) {
|
||||
sendPort.send('Hello from isolate!');
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('Isolate Reflection', () {
|
||||
late RuntimeReflector reflector;
|
||||
|
||||
setUp(() {
|
||||
reflector = RuntimeReflector.instance;
|
||||
});
|
||||
|
||||
test('currentIsolate returns mirror for current isolate', () {
|
||||
final isolateMirror = reflector.currentIsolate;
|
||||
|
||||
expect(isolateMirror, isNotNull);
|
||||
expect(isolateMirror.isCurrent, isTrue);
|
||||
expect(isolateMirror.debugName, equals('main'));
|
||||
expect(isolateMirror.rootLibrary, isNotNull);
|
||||
});
|
||||
|
||||
test('reflectIsolate returns mirror for other isolate', () async {
|
||||
final receivePort = ReceivePort();
|
||||
final isolate = await Isolate.spawn(
|
||||
isolateFunction,
|
||||
receivePort.sendPort,
|
||||
);
|
||||
|
||||
final isolateMirror = reflector.reflectIsolate(isolate, 'test-isolate');
|
||||
|
||||
expect(isolateMirror, isNotNull);
|
||||
expect(isolateMirror.isCurrent, isFalse);
|
||||
expect(isolateMirror.debugName, equals('test-isolate'));
|
||||
expect(isolateMirror.rootLibrary, isNotNull);
|
||||
|
||||
// Clean up
|
||||
receivePort.close();
|
||||
isolate.kill();
|
||||
});
|
||||
|
||||
test('isolate mirror provides control over isolate', () async {
|
||||
final receivePort = ReceivePort();
|
||||
final isolate = await Isolate.spawn(
|
||||
isolateFunction,
|
||||
receivePort.sendPort,
|
||||
);
|
||||
|
||||
final isolateMirror = reflector.reflectIsolate(isolate, 'test-isolate')
|
||||
as IsolateMirrorImpl;
|
||||
|
||||
// Test pause/resume
|
||||
await isolateMirror.pause();
|
||||
await isolateMirror.resume();
|
||||
|
||||
// Test error listener
|
||||
var errorReceived = false;
|
||||
isolateMirror.addErrorListener((error, stackTrace) {
|
||||
errorReceived = true;
|
||||
});
|
||||
|
||||
// Test exit listener
|
||||
var exitReceived = false;
|
||||
isolateMirror.addExitListener((_) {
|
||||
exitReceived = false;
|
||||
});
|
||||
|
||||
// Test kill
|
||||
await isolateMirror.kill();
|
||||
|
||||
// Clean up
|
||||
receivePort.close();
|
||||
});
|
||||
|
||||
test('isolate mirrors compare correctly', () async {
|
||||
final receivePort = ReceivePort();
|
||||
final isolate = await Isolate.spawn(
|
||||
isolateFunction,
|
||||
receivePort.sendPort,
|
||||
);
|
||||
|
||||
final mirror1 = reflector.reflectIsolate(isolate, 'test-isolate');
|
||||
final mirror2 = reflector.reflectIsolate(isolate, 'test-isolate');
|
||||
final mirror3 = reflector.reflectIsolate(isolate, 'other-name');
|
||||
|
||||
expect(mirror1, equals(mirror2));
|
||||
expect(mirror1, isNot(equals(mirror3)));
|
||||
expect(mirror1.hashCode, equals(mirror2.hashCode));
|
||||
expect(mirror1.hashCode, isNot(equals(mirror3.hashCode)));
|
||||
|
||||
// Clean up
|
||||
receivePort.close();
|
||||
isolate.kill();
|
||||
});
|
||||
|
||||
test('isolate mirror toString provides meaningful description', () {
|
||||
final currentMirror = reflector.currentIsolate;
|
||||
expect(
|
||||
currentMirror.toString(), equals('IsolateMirror "main" (current)'));
|
||||
|
||||
final receivePort = ReceivePort();
|
||||
Isolate.spawn(
|
||||
isolateFunction,
|
||||
receivePort.sendPort,
|
||||
).then((isolate) {
|
||||
final otherMirror = reflector.reflectIsolate(isolate, 'test-isolate');
|
||||
expect(otherMirror.toString(), equals('IsolateMirror "test-isolate"'));
|
||||
|
||||
// Clean up
|
||||
receivePort.close();
|
||||
isolate.kill();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
128
packages/reflection/test/library_reflection_test.dart
Normal file
128
packages/reflection/test/library_reflection_test.dart
Normal file
|
@ -0,0 +1,128 @@
|
|||
import 'package:platform_reflection/reflection.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
// Top-level function for testing
|
||||
int add(int a, int b) => a + b;
|
||||
|
||||
// Top-level variable for testing
|
||||
const String greeting = 'Hello';
|
||||
|
||||
void main() {
|
||||
group('Library Reflection', () {
|
||||
late RuntimeReflector reflector;
|
||||
|
||||
setUp(() {
|
||||
reflector = RuntimeReflector.instance;
|
||||
});
|
||||
|
||||
test('reflectLibrary returns library mirror', () {
|
||||
final libraryMirror = reflector.reflectLibrary(
|
||||
Uri.parse('package:reflection/test/library_reflection_test.dart'),
|
||||
);
|
||||
|
||||
expect(libraryMirror, isNotNull);
|
||||
expect(libraryMirror.uri.toString(),
|
||||
contains('library_reflection_test.dart'));
|
||||
});
|
||||
|
||||
test('library mirror provides correct metadata', () {
|
||||
final libraryMirror = reflector.reflectLibrary(
|
||||
Uri.parse('package:reflection/test/library_reflection_test.dart'),
|
||||
);
|
||||
|
||||
expect(libraryMirror.isPrivate, isFalse);
|
||||
expect(libraryMirror.isTopLevel, isTrue);
|
||||
expect(libraryMirror.metadata, isEmpty);
|
||||
});
|
||||
|
||||
test('library mirror provides access to declarations', () {
|
||||
final libraryMirror = reflector.reflectLibrary(
|
||||
Uri.parse('package:reflection/test/library_reflection_test.dart'),
|
||||
);
|
||||
|
||||
final declarations = libraryMirror.declarations;
|
||||
expect(declarations, isNotEmpty);
|
||||
|
||||
// Check for top-level function
|
||||
final addFunction = declarations[const Symbol('add')] as MethodMirror;
|
||||
expect(addFunction, isNotNull);
|
||||
expect(addFunction.isStatic, isTrue);
|
||||
expect(addFunction.parameters.length, equals(2));
|
||||
|
||||
// Check for top-level variable
|
||||
final greetingVar =
|
||||
declarations[const Symbol('greeting')] as VariableMirror;
|
||||
expect(greetingVar, isNotNull);
|
||||
expect(greetingVar.isStatic, isTrue);
|
||||
expect(greetingVar.isConst, isTrue);
|
||||
expect(greetingVar.type.reflectedType, equals(String));
|
||||
});
|
||||
|
||||
test('library mirror provides access to dependencies', () {
|
||||
final libraryMirror = reflector.reflectLibrary(
|
||||
Uri.parse('package:reflection/test/library_reflection_test.dart'),
|
||||
);
|
||||
|
||||
final dependencies = libraryMirror.libraryDependencies;
|
||||
expect(dependencies, isNotEmpty);
|
||||
|
||||
// Check for test package import
|
||||
final testImport = dependencies.firstWhere((dep) =>
|
||||
dep.isImport &&
|
||||
dep.targetLibrary?.uri.toString().contains('package:test/') == true);
|
||||
expect(testImport, isNotNull);
|
||||
expect(testImport.isDeferred, isFalse);
|
||||
expect(testImport.prefix, isNull);
|
||||
|
||||
// Check for reflection package import
|
||||
final reflectionImport = dependencies.firstWhere((dep) =>
|
||||
dep.isImport &&
|
||||
dep.targetLibrary?.uri
|
||||
.toString()
|
||||
.contains('package:platform_reflection/') ==
|
||||
true);
|
||||
expect(reflectionImport, isNotNull);
|
||||
expect(reflectionImport.isDeferred, isFalse);
|
||||
expect(reflectionImport.prefix, isNull);
|
||||
});
|
||||
|
||||
test('library mirror allows invoking top-level functions', () {
|
||||
final libraryMirror = reflector.reflectLibrary(
|
||||
Uri.parse('package:reflection/test/library_reflection_test.dart'),
|
||||
);
|
||||
|
||||
final result = libraryMirror.invoke(
|
||||
const Symbol('add'),
|
||||
[2, 3],
|
||||
).reflectee as int;
|
||||
|
||||
expect(result, equals(5));
|
||||
});
|
||||
|
||||
test('library mirror allows accessing top-level variables', () {
|
||||
final libraryMirror = reflector.reflectLibrary(
|
||||
Uri.parse('package:reflection/test/library_reflection_test.dart'),
|
||||
);
|
||||
|
||||
final value =
|
||||
libraryMirror.getField(const Symbol('greeting')).reflectee as String;
|
||||
expect(value, equals('Hello'));
|
||||
});
|
||||
|
||||
test('library mirror throws on non-existent members', () {
|
||||
final libraryMirror = reflector.reflectLibrary(
|
||||
Uri.parse('package:reflection/test/library_reflection_test.dart'),
|
||||
);
|
||||
|
||||
expect(
|
||||
() => libraryMirror.invoke(const Symbol('nonexistent'), []),
|
||||
throwsA(isA<NoSuchMethodError>()),
|
||||
);
|
||||
|
||||
expect(
|
||||
() => libraryMirror.getField(const Symbol('nonexistent')),
|
||||
throwsA(isA<NoSuchMethodError>()),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
141
packages/reflection/test/mirror_system_test.dart
Normal file
141
packages/reflection/test/mirror_system_test.dart
Normal file
|
@ -0,0 +1,141 @@
|
|||
import 'package:platform_reflection/reflection.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
@reflectable
|
||||
class TestClass {
|
||||
String name;
|
||||
TestClass(this.name);
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('MirrorSystem', () {
|
||||
late RuntimeReflector reflector;
|
||||
late MirrorSystem mirrorSystem;
|
||||
|
||||
setUp(() {
|
||||
reflector = RuntimeReflector.instance;
|
||||
mirrorSystem = reflector.currentMirrorSystem;
|
||||
|
||||
// Register test class
|
||||
Reflector.registerType(TestClass);
|
||||
Reflector.registerPropertyMetadata(
|
||||
TestClass,
|
||||
'name',
|
||||
PropertyMetadata(
|
||||
name: 'name',
|
||||
type: String,
|
||||
isReadable: true,
|
||||
isWritable: true,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('currentMirrorSystem provides access to libraries', () {
|
||||
expect(mirrorSystem.libraries, isNotEmpty);
|
||||
expect(
|
||||
mirrorSystem.libraries.keys
|
||||
.any((uri) => uri.toString() == 'dart:core'),
|
||||
isTrue);
|
||||
});
|
||||
|
||||
test('findLibrary returns correct library', () {
|
||||
final library = mirrorSystem.findLibrary(const Symbol('dart:core'));
|
||||
expect(library, isNotNull);
|
||||
expect(library.uri.toString(), equals('dart:core'));
|
||||
});
|
||||
|
||||
test('findLibrary throws on non-existent library', () {
|
||||
expect(
|
||||
() => mirrorSystem.findLibrary(const Symbol('non:existent')),
|
||||
throwsArgumentError,
|
||||
);
|
||||
});
|
||||
|
||||
test('reflectClass returns class mirror', () {
|
||||
final classMirror = mirrorSystem.reflectClass(TestClass);
|
||||
expect(classMirror, isNotNull);
|
||||
expect(classMirror.name, equals('TestClass'));
|
||||
expect(classMirror.declarations, isNotEmpty);
|
||||
});
|
||||
|
||||
test('reflectClass throws on non-reflectable type', () {
|
||||
expect(
|
||||
() => mirrorSystem.reflectClass(Object),
|
||||
throwsArgumentError,
|
||||
);
|
||||
});
|
||||
|
||||
test('reflectType returns type mirror', () {
|
||||
final typeMirror = mirrorSystem.reflectType(TestClass);
|
||||
expect(typeMirror, isNotNull);
|
||||
expect(typeMirror.name, equals('TestClass'));
|
||||
expect(typeMirror.hasReflectedType, isTrue);
|
||||
expect(typeMirror.reflectedType, equals(TestClass));
|
||||
});
|
||||
|
||||
test('reflectType throws on non-reflectable type', () {
|
||||
expect(
|
||||
() => mirrorSystem.reflectType(Object),
|
||||
throwsArgumentError,
|
||||
);
|
||||
});
|
||||
|
||||
test('isolate returns current isolate mirror', () {
|
||||
final isolateMirror = mirrorSystem.isolate;
|
||||
expect(isolateMirror, isNotNull);
|
||||
expect(isolateMirror.isCurrent, isTrue);
|
||||
expect(isolateMirror.debugName, equals('main'));
|
||||
});
|
||||
|
||||
test('dynamicType returns dynamic type mirror', () {
|
||||
final typeMirror = mirrorSystem.dynamicType;
|
||||
expect(typeMirror, isNotNull);
|
||||
expect(typeMirror.name, equals('dynamic'));
|
||||
});
|
||||
|
||||
test('voidType returns void type mirror', () {
|
||||
final typeMirror = mirrorSystem.voidType;
|
||||
expect(typeMirror, isNotNull);
|
||||
expect(typeMirror.name, equals('void'));
|
||||
});
|
||||
|
||||
test('neverType returns Never type mirror', () {
|
||||
final typeMirror = mirrorSystem.neverType;
|
||||
expect(typeMirror, isNotNull);
|
||||
expect(typeMirror.name, equals('Never'));
|
||||
});
|
||||
|
||||
test('type relationships work correctly', () {
|
||||
final dynamicMirror = mirrorSystem.dynamicType;
|
||||
final voidMirror = mirrorSystem.voidType;
|
||||
final neverMirror = mirrorSystem.neverType;
|
||||
final stringMirror = mirrorSystem.reflectType(String);
|
||||
|
||||
// Never is a subtype of everything
|
||||
expect(neverMirror.isSubtypeOf(dynamicMirror), isTrue);
|
||||
expect(neverMirror.isSubtypeOf(stringMirror), isTrue);
|
||||
|
||||
// Everything is assignable to dynamic
|
||||
expect(stringMirror.isAssignableTo(dynamicMirror), isTrue);
|
||||
expect(neverMirror.isAssignableTo(dynamicMirror), isTrue);
|
||||
|
||||
// void is not assignable to anything (except itself)
|
||||
expect(voidMirror.isAssignableTo(stringMirror), isFalse);
|
||||
expect(voidMirror.isAssignableTo(dynamicMirror), isFalse);
|
||||
expect(voidMirror.isAssignableTo(voidMirror), isTrue);
|
||||
});
|
||||
|
||||
test('library dependencies are tracked', () {
|
||||
final coreLibrary = mirrorSystem.findLibrary(const Symbol('dart:core'));
|
||||
expect(coreLibrary.libraryDependencies, isNotEmpty);
|
||||
|
||||
final imports =
|
||||
coreLibrary.libraryDependencies.where((dep) => dep.isImport).toList();
|
||||
expect(imports, isNotEmpty);
|
||||
|
||||
final exports =
|
||||
coreLibrary.libraryDependencies.where((dep) => dep.isExport).toList();
|
||||
expect(exports, isNotEmpty);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -2,7 +2,7 @@ import 'package:platform_reflection/reflection.dart';
|
|||
import 'package:test/test.dart';
|
||||
|
||||
@reflectable
|
||||
class Person with Reflector {
|
||||
class Person {
|
||||
String name;
|
||||
int age;
|
||||
final String id;
|
||||
|
@ -43,54 +43,124 @@ void main() {
|
|||
|
||||
setUp(() {
|
||||
// Register Person as reflectable
|
||||
Reflector.register(Person);
|
||||
Reflector.registerType(Person);
|
||||
|
||||
// Register properties
|
||||
Reflector.registerProperty(Person, 'name', String);
|
||||
Reflector.registerProperty(Person, 'age', int);
|
||||
Reflector.registerProperty(Person, 'id', String, isWritable: false);
|
||||
Reflector.registerPropertyMetadata(
|
||||
Person,
|
||||
'name',
|
||||
PropertyMetadata(
|
||||
name: 'name',
|
||||
type: String,
|
||||
isReadable: true,
|
||||
isWritable: true,
|
||||
),
|
||||
);
|
||||
|
||||
Reflector.registerPropertyMetadata(
|
||||
Person,
|
||||
'age',
|
||||
PropertyMetadata(
|
||||
name: 'age',
|
||||
type: int,
|
||||
isReadable: true,
|
||||
isWritable: true,
|
||||
),
|
||||
);
|
||||
|
||||
Reflector.registerPropertyMetadata(
|
||||
Person,
|
||||
'id',
|
||||
PropertyMetadata(
|
||||
name: 'id',
|
||||
type: String,
|
||||
isReadable: true,
|
||||
isWritable: false,
|
||||
),
|
||||
);
|
||||
|
||||
// Register methods
|
||||
Reflector.registerMethod(
|
||||
Reflector.registerMethodMetadata(
|
||||
Person,
|
||||
'birthday',
|
||||
[],
|
||||
true,
|
||||
MethodMetadata(
|
||||
name: 'birthday',
|
||||
parameterTypes: [],
|
||||
parameters: [],
|
||||
returnsVoid: true,
|
||||
),
|
||||
);
|
||||
Reflector.registerMethod(
|
||||
|
||||
Reflector.registerMethodMetadata(
|
||||
Person,
|
||||
'greet',
|
||||
[String],
|
||||
false,
|
||||
parameterNames: ['greeting'],
|
||||
MethodMetadata(
|
||||
name: 'greet',
|
||||
parameterTypes: [String],
|
||||
parameters: [
|
||||
ParameterMetadata(
|
||||
name: 'greeting',
|
||||
type: String,
|
||||
isRequired: true,
|
||||
),
|
||||
],
|
||||
returnsVoid: false,
|
||||
),
|
||||
);
|
||||
|
||||
// Register constructors
|
||||
Reflector.registerConstructor(
|
||||
Reflector.registerConstructorMetadata(
|
||||
Person,
|
||||
ConstructorMetadata(
|
||||
name: '',
|
||||
parameterTypes: [String, int, String],
|
||||
parameters: [
|
||||
ParameterMetadata(name: 'name', type: String, isRequired: true),
|
||||
ParameterMetadata(name: 'age', type: int, isRequired: true),
|
||||
ParameterMetadata(
|
||||
name: 'id', type: String, isRequired: true, isNamed: true),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Reflector.registerConstructorFactory(
|
||||
Person,
|
||||
'',
|
||||
(String name, int age, {required String id}) =>
|
||||
Person(name, age, id: id),
|
||||
parameterTypes: [String, int, String],
|
||||
parameterNames: ['name', 'age', 'id'],
|
||||
isRequired: [true, true, true],
|
||||
isNamed: [false, false, true],
|
||||
);
|
||||
|
||||
Reflector.registerConstructor(
|
||||
Reflector.registerConstructorMetadata(
|
||||
Person,
|
||||
ConstructorMetadata(
|
||||
name: 'guest',
|
||||
parameterTypes: [],
|
||||
parameters: [],
|
||||
),
|
||||
);
|
||||
|
||||
Reflector.registerConstructorFactory(
|
||||
Person,
|
||||
'guest',
|
||||
() => Person.guest(),
|
||||
);
|
||||
|
||||
Reflector.registerConstructor(
|
||||
Reflector.registerConstructorMetadata(
|
||||
Person,
|
||||
ConstructorMetadata(
|
||||
name: 'withDefaults',
|
||||
parameterTypes: [String, int],
|
||||
parameters: [
|
||||
ParameterMetadata(name: 'name', type: String, isRequired: true),
|
||||
ParameterMetadata(name: 'age', type: int, isRequired: false),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Reflector.registerConstructorFactory(
|
||||
Person,
|
||||
'withDefaults',
|
||||
(String name, [int age = 18]) => Person.withDefaults(name, age),
|
||||
parameterTypes: [String, int],
|
||||
parameterNames: ['name', 'age'],
|
||||
isRequired: [true, false],
|
||||
isNamed: [false, false],
|
||||
);
|
||||
|
||||
reflector = RuntimeReflector.instance;
|
||||
|
@ -99,20 +169,20 @@ void main() {
|
|||
|
||||
group('Type Reflection', () {
|
||||
test('reflectType returns correct type metadata', () {
|
||||
final metadata = reflector.reflectType(Person);
|
||||
final typeMirror = reflector.reflectType(Person);
|
||||
|
||||
expect(metadata.name, equals('Person'));
|
||||
expect(metadata.properties.length, equals(3));
|
||||
expect(metadata.methods.length, equals(2)); // birthday and greet
|
||||
expect(metadata.constructors.length,
|
||||
expect(typeMirror.name, equals('Person'));
|
||||
expect(typeMirror.properties.length, equals(3));
|
||||
expect(typeMirror.methods.length, equals(2)); // birthday and greet
|
||||
expect(typeMirror.constructors.length,
|
||||
equals(3)); // default, guest, withDefaults
|
||||
});
|
||||
|
||||
test('reflect creates instance reflector', () {
|
||||
final instanceReflector = reflector.reflect(person);
|
||||
test('reflect creates instance mirror', () {
|
||||
final instanceMirror = reflector.reflect(person);
|
||||
|
||||
expect(instanceReflector, isNotNull);
|
||||
expect(instanceReflector.type.name, equals('Person'));
|
||||
expect(instanceMirror, isNotNull);
|
||||
expect(instanceMirror.type.name, equals('Person'));
|
||||
});
|
||||
|
||||
test('throws NotReflectableException for non-reflectable class', () {
|
||||
|
@ -127,28 +197,31 @@ void main() {
|
|||
|
||||
group('Property Access', () {
|
||||
test('getField returns property value', () {
|
||||
final instanceReflector = reflector.reflect(person);
|
||||
final instanceMirror = reflector.reflect(person);
|
||||
|
||||
expect(instanceReflector.getField('name'), equals('John'));
|
||||
expect(instanceReflector.getField('age'), equals(30));
|
||||
expect(instanceReflector.getField('id'), equals('123'));
|
||||
expect(instanceMirror.getField(const Symbol('name')).reflectee,
|
||||
equals('John'));
|
||||
expect(
|
||||
instanceMirror.getField(const Symbol('age')).reflectee, equals(30));
|
||||
expect(instanceMirror.getField(const Symbol('id')).reflectee,
|
||||
equals('123'));
|
||||
});
|
||||
|
||||
test('setField updates property value', () {
|
||||
final instanceReflector = reflector.reflect(person);
|
||||
final instanceMirror = reflector.reflect(person);
|
||||
|
||||
instanceReflector.setField('name', 'Jane');
|
||||
instanceReflector.setField('age', 25);
|
||||
instanceMirror.setField(const Symbol('name'), 'Jane');
|
||||
instanceMirror.setField(const Symbol('age'), 25);
|
||||
|
||||
expect(person.name, equals('Jane'));
|
||||
expect(person.age, equals(25));
|
||||
});
|
||||
|
||||
test('setField throws on final field', () {
|
||||
final instanceReflector = reflector.reflect(person);
|
||||
final instanceMirror = reflector.reflect(person);
|
||||
|
||||
expect(
|
||||
() => instanceReflector.setField('id', '456'),
|
||||
() => instanceMirror.setField(const Symbol('id'), '456'),
|
||||
throwsA(isA<ReflectionException>()),
|
||||
);
|
||||
});
|
||||
|
@ -156,20 +229,21 @@ void main() {
|
|||
|
||||
group('Method Invocation', () {
|
||||
test('invoke calls method with arguments', () {
|
||||
final instanceReflector = reflector.reflect(person);
|
||||
final instanceMirror = reflector.reflect(person);
|
||||
|
||||
final result = instanceReflector.invoke('greet', ['Hello']);
|
||||
final result =
|
||||
instanceMirror.invoke(const Symbol('greet'), ['Hello']).reflectee;
|
||||
expect(result, equals('Hello, John!'));
|
||||
|
||||
instanceReflector.invoke('birthday', []);
|
||||
instanceMirror.invoke(const Symbol('birthday'), []);
|
||||
expect(person.age, equals(31));
|
||||
});
|
||||
|
||||
test('invoke throws on invalid arguments', () {
|
||||
final instanceReflector = reflector.reflect(person);
|
||||
final instanceMirror = reflector.reflect(person);
|
||||
|
||||
expect(
|
||||
() => instanceReflector.invoke('greet', [42]),
|
||||
() => instanceMirror.invoke(const Symbol('greet'), [42]),
|
||||
throwsA(isA<InvalidArgumentsException>()),
|
||||
);
|
||||
});
|
||||
|
|
246
packages/reflection/test/scanner_test.dart
Normal file
246
packages/reflection/test/scanner_test.dart
Normal file
|
@ -0,0 +1,246 @@
|
|||
import 'package:platform_reflection/reflection.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
@reflectable
|
||||
class TestClass {
|
||||
String name;
|
||||
final int id;
|
||||
List<String> tags;
|
||||
static const version = '1.0.0';
|
||||
|
||||
TestClass(this.name, {required this.id, this.tags = const []});
|
||||
|
||||
TestClass.guest()
|
||||
: name = 'Guest',
|
||||
id = 0,
|
||||
tags = const [];
|
||||
|
||||
void addTag(String tag) {
|
||||
tags.add(tag);
|
||||
}
|
||||
|
||||
String greet([String greeting = 'Hello']) {
|
||||
return '$greeting, $name!';
|
||||
}
|
||||
|
||||
static TestClass create(String name, {required int id}) {
|
||||
return TestClass(name, id: id);
|
||||
}
|
||||
}
|
||||
|
||||
@reflectable
|
||||
class GenericTestClass<T> {
|
||||
T value;
|
||||
List<T> items;
|
||||
|
||||
GenericTestClass(this.value, {this.items = const []});
|
||||
|
||||
void addItem(T item) {
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
T getValue() => value;
|
||||
}
|
||||
|
||||
@reflectable
|
||||
class ParentTestClass {
|
||||
String name;
|
||||
ParentTestClass(this.name);
|
||||
|
||||
String getName() => name;
|
||||
}
|
||||
|
||||
@reflectable
|
||||
class ChildTestClass extends ParentTestClass {
|
||||
int age;
|
||||
ChildTestClass(String name, this.age) : super(name);
|
||||
|
||||
@override
|
||||
String getName() => '$name ($age)';
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('Scanner', () {
|
||||
test('scans properties correctly', () {
|
||||
Scanner.scanType(TestClass);
|
||||
final metadata = Reflector.getPropertyMetadata(TestClass);
|
||||
|
||||
expect(metadata, isNotNull);
|
||||
expect(metadata!['name'], isNotNull);
|
||||
expect(metadata['name']!.type, equals(String));
|
||||
expect(metadata['name']!.isWritable, isTrue);
|
||||
|
||||
expect(metadata['id'], isNotNull);
|
||||
expect(metadata['id']!.type, equals(int));
|
||||
expect(metadata['id']!.isWritable, isFalse);
|
||||
|
||||
expect(metadata['tags'], isNotNull);
|
||||
expect(metadata['tags']!.type, equals(List<String>));
|
||||
expect(metadata['tags']!.isWritable, isTrue);
|
||||
|
||||
expect(metadata['version'], isNotNull);
|
||||
expect(metadata['version']!.type, equals(String));
|
||||
expect(metadata['version']!.isWritable, isFalse);
|
||||
});
|
||||
|
||||
test('scans methods correctly', () {
|
||||
Scanner.scanType(TestClass);
|
||||
final metadata = Reflector.getMethodMetadata(TestClass);
|
||||
|
||||
expect(metadata, isNotNull);
|
||||
|
||||
// addTag method
|
||||
expect(metadata!['addTag'], isNotNull);
|
||||
expect(metadata['addTag']!.parameterTypes, equals([String]));
|
||||
expect(metadata['addTag']!.parameters.length, equals(1));
|
||||
expect(metadata['addTag']!.parameters[0].name, equals('tag'));
|
||||
expect(metadata['addTag']!.parameters[0].type, equals(String));
|
||||
expect(metadata['addTag']!.parameters[0].isRequired, isTrue);
|
||||
expect(metadata['addTag']!.returnsVoid, isTrue);
|
||||
expect(metadata['addTag']!.isStatic, isFalse);
|
||||
|
||||
// greet method
|
||||
expect(metadata['greet'], isNotNull);
|
||||
expect(metadata['greet']!.parameterTypes, equals([String]));
|
||||
expect(metadata['greet']!.parameters.length, equals(1));
|
||||
expect(metadata['greet']!.parameters[0].name, equals('greeting'));
|
||||
expect(metadata['greet']!.parameters[0].type, equals(String));
|
||||
expect(metadata['greet']!.parameters[0].isRequired, isFalse);
|
||||
expect(metadata['greet']!.returnsVoid, isFalse);
|
||||
expect(metadata['greet']!.isStatic, isFalse);
|
||||
|
||||
// create method
|
||||
expect(metadata['create'], isNotNull);
|
||||
expect(metadata['create']!.parameterTypes, equals([String, int]));
|
||||
expect(metadata['create']!.parameters.length, equals(2));
|
||||
expect(metadata['create']!.parameters[0].name, equals('name'));
|
||||
expect(metadata['create']!.parameters[0].type, equals(String));
|
||||
expect(metadata['create']!.parameters[0].isRequired, isTrue);
|
||||
expect(metadata['create']!.parameters[1].name, equals('id'));
|
||||
expect(metadata['create']!.parameters[1].type, equals(int));
|
||||
expect(metadata['create']!.parameters[1].isRequired, isTrue);
|
||||
expect(metadata['create']!.parameters[1].isNamed, isTrue);
|
||||
expect(metadata['create']!.returnsVoid, isFalse);
|
||||
expect(metadata['create']!.isStatic, isTrue);
|
||||
});
|
||||
|
||||
test('scans constructors correctly', () {
|
||||
Scanner.scanType(TestClass);
|
||||
final metadata = Reflector.getConstructorMetadata(TestClass);
|
||||
|
||||
expect(metadata, isNotNull);
|
||||
expect(metadata!.length, equals(2));
|
||||
|
||||
// Default constructor
|
||||
final defaultCtor = metadata.firstWhere((m) => m.name.isEmpty);
|
||||
expect(defaultCtor.parameterTypes, equals([String, int, List<String>]));
|
||||
expect(defaultCtor.parameters.length, equals(3));
|
||||
expect(defaultCtor.parameters[0].name, equals('name'));
|
||||
expect(defaultCtor.parameters[0].type, equals(String));
|
||||
expect(defaultCtor.parameters[0].isRequired, isTrue);
|
||||
expect(defaultCtor.parameters[1].name, equals('id'));
|
||||
expect(defaultCtor.parameters[1].type, equals(int));
|
||||
expect(defaultCtor.parameters[1].isRequired, isTrue);
|
||||
expect(defaultCtor.parameters[1].isNamed, isTrue);
|
||||
expect(defaultCtor.parameters[2].name, equals('tags'));
|
||||
expect(defaultCtor.parameters[2].type, equals(List<String>));
|
||||
expect(defaultCtor.parameters[2].isRequired, isFalse);
|
||||
expect(defaultCtor.parameters[2].isNamed, isTrue);
|
||||
|
||||
// Guest constructor
|
||||
final guestCtor = metadata.firstWhere((m) => m.name == 'guest');
|
||||
expect(guestCtor.parameterTypes, isEmpty);
|
||||
expect(guestCtor.parameters, isEmpty);
|
||||
});
|
||||
|
||||
test('scanned type works with reflection', () {
|
||||
Scanner.scanType(TestClass);
|
||||
final reflector = RuntimeReflector.instance;
|
||||
|
||||
// Create instance
|
||||
final instance = reflector.createInstance(
|
||||
TestClass,
|
||||
positionalArgs: ['John'],
|
||||
namedArgs: {'id': 123},
|
||||
) as TestClass;
|
||||
|
||||
expect(instance.name, equals('John'));
|
||||
expect(instance.id, equals(123));
|
||||
expect(instance.tags, isEmpty);
|
||||
|
||||
// Create guest instance
|
||||
final guest = reflector.createInstance(
|
||||
TestClass,
|
||||
constructorName: 'guest',
|
||||
) as TestClass;
|
||||
|
||||
expect(guest.name, equals('Guest'));
|
||||
expect(guest.id, equals(0));
|
||||
expect(guest.tags, isEmpty);
|
||||
|
||||
// Reflect on instance
|
||||
final mirror = reflector.reflect(instance);
|
||||
|
||||
// Access properties
|
||||
expect(mirror.getField(const Symbol('name')).reflectee, equals('John'));
|
||||
expect(mirror.getField(const Symbol('id')).reflectee, equals(123));
|
||||
|
||||
// Modify properties
|
||||
mirror.setField(const Symbol('name'), 'Jane');
|
||||
expect(instance.name, equals('Jane'));
|
||||
|
||||
// Invoke methods
|
||||
mirror.invoke(const Symbol('addTag'), ['test']);
|
||||
expect(instance.tags, equals(['test']));
|
||||
|
||||
final greeting = mirror.invoke(const Symbol('greet'), ['Hi']).reflectee;
|
||||
expect(greeting, equals('Hi, Jane!'));
|
||||
|
||||
// Try to modify final field (should throw)
|
||||
expect(
|
||||
() => mirror.setField(const Symbol('id'), 456),
|
||||
throwsA(isA<ReflectionException>()),
|
||||
);
|
||||
});
|
||||
|
||||
test('handles generic types correctly', () {
|
||||
Scanner.scanType(GenericTestClass);
|
||||
final metadata = Reflector.getPropertyMetadata(GenericTestClass);
|
||||
|
||||
expect(metadata, isNotNull);
|
||||
expect(metadata!['value'], isNotNull);
|
||||
expect(metadata['items'], isNotNull);
|
||||
expect(metadata['items']!.type, equals(List));
|
||||
|
||||
final methodMeta = Reflector.getMethodMetadata(GenericTestClass);
|
||||
expect(methodMeta, isNotNull);
|
||||
expect(methodMeta!['addItem'], isNotNull);
|
||||
expect(methodMeta['getValue'], isNotNull);
|
||||
});
|
||||
|
||||
test('handles inheritance correctly', () {
|
||||
Scanner.scanType(ParentTestClass);
|
||||
Scanner.scanType(ChildTestClass);
|
||||
|
||||
final parentMeta = Reflector.getPropertyMetadata(ParentTestClass);
|
||||
final childMeta = Reflector.getPropertyMetadata(ChildTestClass);
|
||||
|
||||
expect(parentMeta, isNotNull);
|
||||
expect(parentMeta!['name'], isNotNull);
|
||||
|
||||
expect(childMeta, isNotNull);
|
||||
expect(childMeta!['name'], isNotNull);
|
||||
expect(childMeta['age'], isNotNull);
|
||||
|
||||
final reflector = RuntimeReflector.instance;
|
||||
final child = reflector.createInstance(
|
||||
ChildTestClass,
|
||||
positionalArgs: ['John', 30],
|
||||
) as ChildTestClass;
|
||||
|
||||
final mirror = reflector.reflect(child);
|
||||
final result = mirror.invoke(const Symbol('getName'), []).reflectee;
|
||||
expect(result, equals('John (30)'));
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue