Compare commits

..

15 commits

Author SHA1 Message Date
Patrick Stewart
1007479792 update: adding tool dir to melos system 2024-11-11 12:52:28 -07:00
Patrick Stewart
7bf27e2e59 remove: deleting .gitkeep 2024-11-11 12:51:31 -07:00
Patrick Stewart
23c9e2b107 add: adding scripts for vscode setup 2024-11-11 12:51:08 -07:00
Patrick Stewart
16c1047bfe remove: removing support for devbox 2024-11-11 12:50:45 -07:00
Patrick Stewart
83fd901968 refactored: cleanup from refactoring 2024-11-11 12:50:12 -07:00
Patrick Stewart
601a5e6210 refactored: refactored mocking, exception to testing, support packages 2024-11-11 12:49:32 -07:00
Patrick Stewart
cb16079d14 refactored: refactored exceptions package to support 2024-11-11 12:47:52 -07:00
Patrick Stewart
a0d5f68fad refactor: refactored mocking package to testing 2024-11-11 12:46:51 -07:00
Patrick Stewart
b42e1daa89 add: adding support for project static website generation 2024-11-11 12:43:18 -07:00
Patrick Stewart
df19fbea36 add: adding extract/converter tool (wip) 2024-11-11 12:40:51 -07:00
Patrick Stewart
a4beca5a4c update: updating melos config guide minor cleanup 2024-10-28 00:05:29 -07:00
Patrick Stewart
999b7acb5a add: adding support for custom templates 2024-10-27 23:24:00 -07:00
Patrick Stewart
c7e69edcfc add: adding support for custom after prompts 2024-10-27 22:55:11 -07:00
Patrick Stewart
a63b2097a4 add: adding support for creating dart/flutter packages 2024-10-27 22:54:30 -07:00
Patrick Stewart
d17bfcf09a add: adding support for building apps in the monorepo 2024-10-27 22:53:50 -07:00
114 changed files with 6180 additions and 790 deletions

View file

View file

@ -1,7 +1,9 @@
name: protevus_platform name: protevus_platform
repository: https://github.com/protevus/platform repository: https://github.com/protevus/platform
packages: packages:
- apps/**
- packages/** - packages/**
- helpers/tools/**
- examples/** - examples/**
command: command:

View file

@ -1,5 +1,5 @@
scripts: scripts:
_: &workflow_scripts _: &create_scripts
clean: clean:
run: > run: >
melos exec -c 1 --fail-fast -- " melos exec -c 1 --fail-fast -- "

24
.melos/create.yaml Normal file
View file

@ -0,0 +1,24 @@
scripts:
_: &create_scripts
create:
name: Create new package or application
description: |
Creates a new Dart package or Flutter application in the appropriate directory.
Usage: melos run create -- --type dart|flutter --category type --name project_name
Available categories for Dart:
- package : Basic Dart package
- console : Command-line application
- server : Server-side application
- desktop : Desktop application
- plugin : Dart plugin
Available categories for Flutter:
- app : Mobile application
- web : Web application
- desktop : Desktop application
- plugin : Flutter plugin
- module : Flutter module
- package : Flutter package
run: dart run helpers/create_project.dart $MELOS_ARGS

13
.melos/template.yaml Normal file
View file

@ -0,0 +1,13 @@
scripts:
_: &template_scripts
template:
name: Create from template
description: |
Creates a new project from a template in the templates directory.
Usage: melos run template template_name:name type:dart|flutter name:project_name
Example:
melos run template template_name:bloc_app type:flutter name:my_new_app
melos run template template_name:core_package type:dart name:core_utils
run: dart run helpers/create_from_template.dart $MELOS_ARGS

View file

@ -1,16 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.11.0/.schema/devbox.schema.json",
"packages": [
"dart@latest"
],
"shell": {
"init_hook": [
"echo 'Welcome to Protevus!' > /dev/null"
],
"scripts": {
"test": [
"echo \"Error: no test specified\" && exit 1"
]
}
}
}

View file

@ -1,53 +0,0 @@
{
"lockfile_version": "1",
"packages": {
"dart@latest": {
"last_modified": "2024-06-03T07:19:07Z",
"resolved": "github:NixOS/nixpkgs/4a4ecb0ab415c9fccfb005567a215e6a9564cdf5#dart",
"source": "devbox-search",
"version": "3.4.2",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/9piqr817cdsgmz31m8q723lxhcpgqsa4-dart-3.4.2",
"default": true
}
],
"store_path": "/nix/store/9piqr817cdsgmz31m8q723lxhcpgqsa4-dart-3.4.2"
},
"aarch64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/1j3h5yqxvgzakv5gir1ssg7wggwxhmsd-dart-3.4.2",
"default": true
}
],
"store_path": "/nix/store/1j3h5yqxvgzakv5gir1ssg7wggwxhmsd-dart-3.4.2"
},
"x86_64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/k8a6gkss3s19p5dhbzgbdqqk5b8qzd7d-dart-3.4.2",
"default": true
}
],
"store_path": "/nix/store/k8a6gkss3s19p5dhbzgbdqqk5b8qzd7d-dart-3.4.2"
},
"x86_64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/wbj1csi5fk2w99aiglwgg1mv406pw4pn-dart-3.4.2",
"default": true
}
],
"store_path": "/nix/store/wbj1csi5fk2w99aiglwgg1mv406pw4pn-dart-3.4.2"
}
}
}
}
}

View file

@ -1,328 +0,0 @@
# Protevus Platform Melos Configuration Documentation
## Overview
The Protevus Platform uses Melos to manage our monorepo structure and automate various development tasks. This comprehensive guide outlines the features provided by our Melos configuration and provides detailed instructions on how to use them effectively.
## Repository Structure
- Project name: `protevus_platform`
- Repository: `https://github.com/protevus/platform`
- Package locations:
- `packages/`: Core packages of the platform
- `examples/`: Example applications and usage demonstrations
## Version Control Integration
- Version bump commit message format: "chore: Bump version to %v"
- Changelog:
- Version commits are linked in the changelog
- A workspace-level changelog is generated
- Main versioning branch: `main`
Example of how versioning works:
```bash
# To bump the version and generate changelog
melos version --yes
# To bump a specific version
melos version 1.2.3 --yes
# To bump a prerelease version
melos version prerelease --preid beta --yes
```
## IDE Integration
- IntelliJ integration is disabled to prevent conflicts with our custom setup.
## Available Scripts
### Static Analysis and Formatting
1. **Analyze**
- Command: `melos run analyze`
- Description: Runs `dart analyze` on all packages to identify potential issues.
- Usage: `melos run analyze`
- Example output:
```
Analyzing package_1...
No issues found!
Analyzing package_2...
info • Unused import • lib/src/unused_file.dart:3:8 • unused_import
```
2. **Format**
- Command: `melos run format`
- Description: Formats all Dart files in the repository using `dart format`.
- Usage: `melos run format`
- Example:
```bash
# Format and show which files were changed
melos run format -- -o write --set-exit-if-changed
```
### Code Generation
3. **Generate**
- Command: `melos run generate`
- Description: Runs `build_runner` for code generation in all packages.
- Usage: `melos run generate`
- Example output:
```
Running build_runner for package_1...
[INFO] Generating build script...
[INFO] Generating build script completed, took 304ms
[INFO] Running build...
[INFO] 5 outputs were generated
[INFO] Running build completed, took 2.8s
```
4. **Generate Custom**
- Command: `melos run generate:custom`
- Description: Runs code generation for specified packages.
- Usage: `MELOS_SCOPE="package_name1,package_name2" melos run generate:custom`
- Example:
```bash
MELOS_SCOPE="auth_package,user_package" melos run generate:custom
```
5. **Generate Check**
- Command: `melos run generate:check`
- Description: Checks if code generation is needed in specified packages.
- Usage: `MELOS_SCOPE="package_name" melos run generate:check`
- Example output:
```
Checking auth_package...
Package auth_package needs code generation.
Checking user_package...
Package user_package does not use build_runner.
```
6. **Generate Dummy Test**
- Command: `melos run generate:dummy:test`
- Description: Generates a dummy test file in specified package(s).
- Usage: `MELOS_SCOPE="package_name" melos run generate:dummy:test`
- Example:
```bash
MELOS_SCOPE="new_feature" melos run generate:dummy:test
# This will create a file: new_feature/test/dummy_test.dart
```
### Publishing
7. **Publish**
- Command: `melos run publish`
- Description: Publishes all packages that have changed.
- Usage: `melos run publish`
- Example workflow:
```bash
# First, check what would be published
melos run publish:check
# If everything looks good, publish
melos run publish
```
8. **Publish Check**
- Command: `melos run publish:check`
- Description: Dry run to check which packages would be published.
- Usage: `melos run publish:check`
- Example output:
```
Would publish the following packages:
- auth_package (1.0.0 -> 1.0.1)
- user_package (2.1.0 -> 2.2.0)
```
### Documentation
9. **Generate Docs**
- Command: `melos run docs:generate`
- Description: Generates dartdoc documentation for all packages.
- Usage: `melos run docs:generate`
10. **Generate Custom Docs**
- Command: `melos run docs:generate:custom`
- Description: Generates documentation for specified packages.
- Usage: `MELOS_SCOPE="package_name1,package_name2" melos run docs:generate:custom`
- Example:
```bash
MELOS_SCOPE="core_package,utils_package" melos run docs:generate:custom
```
11. **Serve Docs**
- Command: `melos run docs:serve`
- Description: Serves generated documentation using `dhttpd`.
- Usage: `melos run docs:serve`
- After running, visit `http://localhost:8080` in your browser
12. **Serve Custom Docs**
- Command: `melos run docs:serve:custom`
- Description: Serves documentation for specified packages.
- Usage: `MELOS_SCOPE="package_name" DOC_PORT=8081 melos run docs:serve:custom`
- Example:
```bash
MELOS_SCOPE="api_package" DOC_PORT=8082 melos run docs:serve:custom
# Then visit http://localhost:8082 in your browser
```
### Testing
13. **Test**
- Command: `melos run test`
- Description: Runs tests for all packages with fail-fast option.
- Usage: `melos run test`
- Example output:
```
Running tests for auth_package...
00:01 +10: All tests passed!
Running tests for user_package...
00:02 +15: All tests passed!
```
14. **Test Custom**
- Command: `melos run test:custom`
- Description: Runs tests for specified packages.
- Usage: `MELOS_SCOPE="package_name1,package_name2" melos run test:custom`
- Example:
```bash
MELOS_SCOPE="auth_package,user_package" melos run test:custom -- --coverage
```
### Dependency Management
15. **Check Dependencies**
- Command: `melos run deps:check`
- Description: Checks for outdated dependencies in all packages.
- Usage: `melos run deps:check`
- Example output:
```
Checking dependencies for auth_package...
2 dependencies are out of date
Checking dependencies for user_package...
All dependencies up to date
```
16. **Upgrade Dependencies**
- Command: `melos run deps:upgrade`
- Description: Upgrades all dependencies to their latest versions.
- Usage: `melos run deps:upgrade`
17. **Upgrade Custom Dependencies**
- Command: `melos run deps:upgrade:custom`
- Description: Upgrades dependencies for specified packages.
- Usage: `MELOS_SCOPE="package_name1,package_name2" melos run deps:upgrade:custom`
- Example:
```bash
MELOS_SCOPE="database_package,api_package" melos run deps:upgrade:custom
```
### CI/CD
18. **CI Pipeline**
- Command: `melos run ci`
- Description: Runs the full CI pipeline (analyze and test).
- Usage: `melos run ci`
- This is typically used in CI/CD environments, e.g., in a GitHub Actions workflow:
```yaml
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
- run: dart pub global activate melos
- run: melos bootstrap
- run: melos run ci
```
### Debugging and Utility Scripts
19. **Debug Package Name**
- Command: `melos run debug_pkg_name`
- Description: Outputs the name of each package in the workspace.
- Usage: `melos run debug_pkg_name`
- Example output:
```
Package name is auth_package
Package name is user_package
Package name is core_package
```
20. **Debug Package Path**
- Command: `melos run debug_pkg_path`
- Description: Outputs the path of each package in the workspace.
- Usage: `melos run debug_pkg_path`
- Example output:
```
Package path is /home/user/protevus_platform/packages/auth_package
Package path is /home/user/protevus_platform/packages/user_package
```
21. **Debug Reflectable**
- Command: `melos run debug:reflectable`
- Description: Finds `.reflectable.dart` files in specified packages.
- Usage: `MELOS_SCOPE="package_name" melos run debug:reflectable`
- Example:
```bash
MELOS_SCOPE="core_package" melos run debug:reflectable
# Output: Checking for .reflectable.dart files in core_package
# /home/user/protevus_platform/packages/core_package/lib/src/models.reflectable.dart
```
22. **List Dart Files**
- Command: `melos run list:dart:files`
- Description: Lists all Dart files in specified package(s).
- Usage: `MELOS_SCOPE="package_name" melos run list:dart:files`
- Example:
```bash
MELOS_SCOPE="utils_package" melos run list:dart:files
# Output: Listing all Dart files in utils_package:
# /home/user/protevus_platform/packages/utils_package/lib/src/string_utils.dart
# /home/user/protevus_platform/packages/utils_package/lib/src/date_utils.dart
```
23. **Combine Config**
- Command: `melos run combine_config`
- Description: Combines Melos configuration files using a custom script.
- Usage: `melos run combine_config`
- This is useful for maintaining separate config files for different environments or CI/CD pipelines.
## Advanced Usage Examples
1. Running a subset of tests matching a specific pattern:
```bash
MELOS_SCOPE="auth_package" melos run test:custom -- --name "login"
```
2. Generating documentation and immediately serving it:
```bash
melos run docs:generate && melos run docs:serve
```
3. Checking for outdated dependencies, upgrading them, and then running tests:
```bash
melos run deps:check && melos run deps:upgrade && melos run test
```
4. Performing a dry-run of publishing, then actually publishing if everything looks good:
```bash
melos run publish:check && melos run publish
```
5. Running the full CI pipeline and then generating documentation if CI passes:
```bash
melos run ci && melos run docs:generate
```
6. Upgrading dependencies for multiple packages and then running their tests:
```bash
MELOS_SCOPE="auth_package,user_package,core_package" melos run deps:upgrade:custom && MELOS_SCOPE="auth_package,user_package,core_package" melos run test:custom
```
7. Generating code, running tests, and then checking if any files need to be formatted:
```bash
melos run generate && melos run test && melos run format -- -o none --set-exit-if-changed
```
This documentation provides a comprehensive guide to using the Melos configuration in the Protevus Platform project. It covers all aspects of the development lifecycle and should help team members effectively manage the monorepo structure.

644
docs/melos_config.md Normal file
View file

@ -0,0 +1,644 @@
```markdown
# Protevus Platform Melos Configuration Documentation
## Table of Contents
- [Overview](#overview)
- [Repository Structure](#repository-structure)
- [Setup and Configuration](#setup-and-configuration)
- [Version Control Integration](#version-control-integration)
- [Project Management](#project-management)
- [Development Workflow](#development-workflow)
- [Testing and Coverage](#testing-and-coverage)
- [Documentation](#documentation)
- [Code Generation](#code-generation)
- [Dependency Management](#dependency-management)
- [CI/CD](#cicd)
- [Debugging and Utilities](#debugging-and-utilities)
- [Advanced Usage](#advanced-usage)
- [Best Practices](#best-practices)
## Overview
The Protevus Platform uses Melos to manage our monorepo structure and automate various development tasks. This comprehensive guide outlines the features provided by our Melos configuration and provides detailed instructions on how to use them effectively.
### Project Information
- Project name: `protevus_platform`
- Repository: `https://github.com/protevus/platform`
### Directory Structure
```
project/
├── apps/ # Flutter applications
├── packages/ # Dart/Flutter packages
├── examples/ # Example projects
├── templates/ # Project templates
├── tools/ # Build and maintenance scripts
└── config/ # Configuration files
```
## Setup and Configuration
### Initial Setup
```bash
# Configure the entire development environment
melos run configure
```
This command performs a comprehensive setup:
1. Bootstraps the workspace
2. Generates code for platform_container_generator
3. Creates dummy tests for specific packages
4. Runs reflectable debugging
5. Executes test suite
6. Generates coverage reports
7. Creates API documentation
### IDE Integration
- IntelliJ integration is disabled to prevent conflicts with our custom setup.
### Configuration Management
```bash
# Combine configuration files
melos run combine_config
```
Combines multiple configuration files:
- analyze.yaml
- generate.yaml
- publish.yaml
- docs.yaml
- coverage.yaml
- clean.yaml
- configure.yaml
- test.yaml
- create.yaml
- dependencies.yaml
- ci.yaml
- debug.yaml
- utils.yaml
## Version Control Integration
### Version Management
- Version bump commit message format: "chore: Bump version to %v"
- Main versioning branch: `main`
- Changelog features:
- Version commits are linked
- Workspace-level changelog generation
Example version management:
```bash
# Standard version bump
melos version --yes
# Specific version bump
melos version 1.2.3 --yes
# Prerelease version
melos version prerelease --preid beta --yes
```
## Project Management
### Creating New Projects
#### Standard Project Creation
```bash
melos run create -- --type <dart|flutter> --category <category> --name <name>
```
##### Categories for Dart Projects:
- `package`: Standard Dart package
- `console`: Command-line application
- `server`: Server-side application with built-in dependencies:
- shelf_router
- dotenv
- logger
- `desktop`: Desktop application with:
- window_manager
- screen_retriever
- `plugin`: Dart plugin package
##### Categories for Flutter Projects:
- `app`: Standard mobile application
- `web`: Web-optimized application
- `desktop`: Multi-platform desktop application
- `plugin`: Flutter plugin
- `module`: Add-to-app module
- `package`: Flutter-specific package
#### Template-Based Project Creation
```bash
melos run template template_name:<template> type:<dart|flutter> name:<project_name>
```
##### Template System Features:
- Templates stored in `templates/` directory
- Variable substitution using placeholders:
- `{{PROJECT_NAME}}`: Raw project name
- `{{PROJECT_NAME_SNAKE_CASE}}`: Snake case version
- `{{PROJECT_NAME_PASCAL_CASE}}`: Pascal case version
- `{{PROJECT_NAME_CAMEL_CASE}}`: Camel case version
- `{{CREATION_TIMESTAMP}}`: Creation timestamp
Example template usage:
```bash
# Create a new Flutter app from the bloc_app template
melos run template template_name:bloc_app type:flutter name:my_new_app
# Create a new Dart package from a core template
melos run template template_name:core_package type:dart name:core_utils
```
## Development Workflow
### Static Analysis and Formatting
#### Code Analysis
```bash
# Run static analysis
melos run analyze
```
Example output:
```
Analyzing package_1...
No issues found!
Analyzing package_2...
info • Unused import • lib/src/unused_file.dart:3:8 • unused_import
```
#### Code Formatting
```bash
# Format all Dart files
melos run format
# Format and check for changes
melos run format -- -o write --set-exit-if-changed
```
### Code Generation
#### Generate for All Packages
```bash
# Run build_runner for all packages
melos run generate
```
Example output:
```
Running build_runner for package_1...
[INFO] Generating build script...
[INFO] Generating build script completed, took 304ms
[INFO] Running build...
[INFO] 5 outputs were generated
[INFO] Running build completed, took 2.8s
```
#### Generate for Specific Packages
```bash
# Run code generation for specified packages
MELOS_SCOPE="package_name1,package_name2" melos run generate:custom
```
#### Check Generation Status
```bash
# Check if code generation is needed
MELOS_SCOPE="package_name" melos run generate:check
```
Example output:
```
Checking auth_package...
Package auth_package needs code generation.
Checking user_package...
Package user_package does not use build_runner.
```
#### Generate Dummy Tests
```bash
# Generate dummy test files
MELOS_SCOPE="package_name" melos run generate:dummy:test
```
## Testing and Coverage
### Running Tests
#### All Packages
```bash
# Run all tests
melos run test
```
Example output:
```
Running tests for auth_package...
00:01 +10: All tests passed!
Running tests for user_package...
00:02 +15: All tests passed!
```
#### Specific Packages
```bash
# Run tests for specific packages
MELOS_SCOPE="package_name1,package_name2" melos run test:custom
```
### Coverage Tools
#### Generate Coverage
```bash
# Generate coverage reports
melos run coverage
```
Features:
- Adds coverage dependency temporarily
- Generates LCOV reports
- Removes coverage dependency after completion
#### Coverage Report
```bash
# Generate HTML coverage report
melos run coverage_report
```
Features:
- Generates HTML reports from LCOV data
- Creates detailed coverage visualization
- Provides package-level coverage metrics
## Documentation
### API Documentation Generation
#### Generate for All Packages
```bash
# Generate docs for all packages
melos run docs:generate
#### Generate for Specific Packages
```bash
# Generate docs for specific packages
MELOS_SCOPE="package_name1,package_name2" melos run docs:generate:custom
# Example
MELOS_SCOPE="core_package,utils_package" melos run docs:generate:custom
```
### Serving Documentation
#### Serve All Documentation
```bash
# Serve generated documentation
melos run docs:serve
```
After running, visit `http://localhost:8080` in your browser
#### Serve Specific Package Documentation
```bash
# Serve docs for specific packages with custom port
MELOS_SCOPE="package_name" DOC_PORT=8081 melos run docs:serve:custom
# Example
MELOS_SCOPE="api_package" DOC_PORT=8082 melos run docs:serve:custom
```
## Publishing
### Publishing Packages
#### Check Publication Status
```bash
# Dry run to check what would be published
melos run publish:check
```
Example output:
```
Would publish the following packages:
- auth_package (1.0.0 -> 1.0.1)
- user_package (2.1.0 -> 2.2.0)
```
#### Publish Packages
```bash
# Publish all changed packages
melos run publish
```
Recommended workflow:
```bash
# First, check what would be published
melos run publish:check
# If everything looks good, publish
melos run publish
```
## Dependency Management
### Checking Dependencies
```bash
# Check for outdated dependencies
melos run deps:check
```
Example output:
```
Checking dependencies for auth_package...
2 dependencies are out of date
Checking dependencies for user_package...
All dependencies up to date
```
### Upgrading Dependencies
#### All Packages
```bash
# Upgrade all dependencies
melos run deps:upgrade
```
#### Specific Packages
```bash
# Upgrade dependencies for specific packages
MELOS_SCOPE="package_name1,package_name2" melos run deps:upgrade:custom
# Example
MELOS_SCOPE="database_package,api_package" melos run deps:upgrade:custom
```
## CI/CD
### Continuous Integration
```bash
# Run full CI pipeline
melos run ci
```
This command runs:
1. Static analysis (`analyze`)
2. All tests (`test`)
Example GitHub Actions workflow:
```yaml
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
- run: dart pub global activate melos
- run: melos bootstrap
- run: melos run ci
```
### Maintenance and Cleanup
#### Clean Command
```bash
# Clean all generated files and build artifacts
melos run clean
```
The clean command removes:
- Build directories
- Generated files:
- `.g.dart`
- `.freezed.dart`
- `.mocks.dart`
- `.gr.dart`
- `.config.dart`
- `.reflectable.dart`
- And many more
- Compilation artifacts:
- `.g.aot`
- `.g.ddc`
- `.g.js`
- `.g.js.map`
- `.g.part`
- `.g.sum`
- `.g.txt`
- Coverage files and reports
- Documentation build files
## Debugging and Utility Scripts
### Package Information
#### Debug Package Names
```bash
# Show all package names
melos run debug_pkg_name
```
Example output:
```
Package name is auth_package
Package name is user_package
Package name is core_package
```
#### Debug Package Paths
```bash
# Show all package paths
melos run debug_pkg_path
```
Example output:
```
Package path is /home/user/protevus_platform/packages/auth_package
Package path is /home/user/protevus_platform/packages/user_package
```
### Code Analysis Tools
#### Debug Reflectable Files
```bash
# Find .reflectable.dart files
MELOS_SCOPE="package_name" melos run debug:reflectable
# Example
MELOS_SCOPE="core_package" melos run debug:reflectable
```
Example output:
```
Checking for .reflectable.dart files in core_package
/home/user/protevus_platform/packages/core_package/lib/src/models.reflectable.dart
```
#### List Dart Files
```bash
# List all Dart files in package(s)
MELOS_SCOPE="package_name" melos run list:dart:files
```
Example output:
```
Listing all Dart files in utils_package:
/home/user/protevus_platform/packages/utils_package/lib/src/string_utils.dart
/home/user/protevus_platform/packages/utils_package/lib/src/date_utils.dart
```
### Help System
```bash
# Display all available commands
melos run help
```
## Advanced Usage Examples
### Complex Workflows
#### Running Specific Test Patterns
```bash
# Run tests matching a pattern
MELOS_SCOPE="auth_package" melos run test:custom -- --name "login"
```
#### Documentation Workflow
```bash
# Generate and serve documentation
melos run docs:generate && melos run docs:serve
```
#### Dependency Update Workflow
```bash
# Check, upgrade, and test
melos run deps:check && melos run deps:upgrade && melos run test
```
#### Publishing Workflow
```bash
# Check and publish if everything is okay
melos run publish:check && melos run publish
```
#### CI and Documentation
```bash
# Run CI and generate docs if successful
melos run ci && melos run docs:generate
```
#### Multi-package Operations
```bash
# Upgrade dependencies and run tests for multiple packages
MELOS_SCOPE="auth_package,user_package,core_package" melos run deps:upgrade:custom && \
MELOS_SCOPE="auth_package,user_package,core_package" melos run test:custom
```
#### Code Generation and Verification
```bash
# Generate code, test, and check formatting
melos run generate && melos run test && melos run format -- -o none --set-exit-if-changed
```
## Best Practices
### Project Organization
1. **Directory Structure**
- Place Flutter apps in `apps/`
- Place packages in `packages/`
- Keep examples in `examples/`
- Store templates in `templates/`
- Maintain tools in `tools/`
2. **Template Usage**
- Use `.tmpl` extension for files requiring variable substitution
- Document template variables in README files
- Keep templates minimal and focused
3. **Configuration Management**
- Keep configuration files modular in `config/` directory
- Run `melos combine_config` after configuration changes
- Use environment variables for flexible configuration
### Development Workflow
1. **Before Committing**
```bash
melos run format
melos run analyze
melos run test
```
2. **After Dependency Changes**
```bash
melos bootstrap
melos run deps:check
```
3. **Before Publishing**
```bash
melos run publish:check
melos run test
melos run docs:generate
```
### Code Quality
1. **Testing**
- Maintain high test coverage
- Run `melos run coverage` regularly
- Review coverage reports
2. **Documentation**
- Document all public APIs
- Keep README files updated
- Generate and review documentation
3. **Code Generation**
- Check generation status before commits
- Keep generated files up to date
- Validate generated code
### Environment Variables
Key environment variables used across commands:
- `MELOS_SCOPE`: Target specific packages
- `DOC_PORT`: Custom documentation server port
- `MELOS_ROOT_PATH`: Root directory path
- `MELOS_PACKAGE_NAME`: Current package name
- `MELOS_PACKAGE_PATH`: Current package path
## Support and Resources
### Getting Help
1. Run `melos run help` for command documentation
2. Check package-specific README files
3. Review generated documentation
4. Consult the Melos documentation
### Common Issues
1. **Missing Dependencies**
```bash
melos bootstrap
```
2. **Outdated Generated Code**
```bash
melos run generate
```
3. **Configuration Issues**
```bash
melos run combine_config
```
### Maintenance Tasks
Regular maintenance checklist:
1. Update dependencies regularly
2. Clean generated files periodically
3. Review and update documentation
4. Monitor test coverage
5. Validate templates
6. Check for outdated configurations
This completes the comprehensive documentation of the Protevus Platform Melos configuration system.

View file

@ -0,0 +1,182 @@
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:yaml/yaml.dart';
void main(List<String> args) async {
// Parse command line arguments
String? templateName;
String? projectType;
String? name;
for (var arg in args) {
final parts = arg.split(':');
if (parts.length == 2) {
switch (parts[0]) {
case 'template_name':
templateName = parts[1];
break;
case 'type':
projectType = parts[1];
break;
case 'name':
name = parts[1];
break;
}
}
}
// Print received arguments for debugging
print('Received arguments:');
print('Template Name: $templateName');
print('Project Type: $projectType');
print('Name: $name');
// Validate inputs
if (templateName == null || projectType == null || name == null) {
print('Error: Missing required arguments');
print(
'Usage: melos run template template_name:name type:dart|flutter name:project_name');
exit(1);
}
if (projectType != 'dart' && projectType != 'flutter') {
print('Error: type must be either "dart" or "flutter"');
exit(1);
}
// Convert name to snake_case
final snakeCaseName = name
.replaceAllMapped(
RegExp(r'[A-Z]'),
(match) => '_${match.group(0)?.toLowerCase()}',
)
.toLowerCase()
.replaceFirst(RegExp(r'^_'), '');
// Determine directories
final templateDir = Directory('templates/$templateName');
final targetBaseDir = (projectType == 'flutter') ? 'apps' : 'packages';
final targetDir = Directory('$targetBaseDir/$snakeCaseName');
// Validate template exists
if (!await templateDir.exists()) {
print('Error: Template "$templateName" not found in templates directory');
print('Available templates:');
await for (var entity in Directory('templates').list()) {
if (entity is Directory) {
print(' - ${path.basename(entity.path)}');
}
}
exit(1);
}
// Check if target directory already exists
if (await targetDir.exists()) {
print('Error: Target directory already exists at ${targetDir.path}');
exit(1);
}
try {
// Create target directory
await targetDir.create(recursive: true);
// Copy template files
await _copyDirectory(templateDir, targetDir);
// Process template files
await _processTemplateFiles(targetDir, {
'PROJECT_NAME': name,
'PROJECT_NAME_SNAKE_CASE': snakeCaseName,
'PROJECT_NAME_PASCAL_CASE': _toPascalCase(name),
'PROJECT_NAME_CAMEL_CASE': _toCamelCase(name),
'CREATION_TIMESTAMP': DateTime.now().toIso8601String(),
});
// Update pubspec.yaml if it exists
final pubspecFile = File('${targetDir.path}/pubspec.yaml');
if (await pubspecFile.exists()) {
await _updatePubspec(pubspecFile, name);
}
print(
'Successfully created project from template "$templateName" at ${targetDir.path}');
print('Done! 🎉');
print('To get started, cd into ${targetDir.path}');
} catch (e) {
print('Error: $e');
// Cleanup on error
if (await targetDir.exists()) {
await targetDir.delete(recursive: true);
}
exit(1);
}
}
Future<void> _copyDirectory(Directory source, Directory target) async {
await for (var entity in source.list(recursive: false)) {
final targetPath =
path.join(target.path, path.relative(entity.path, from: source.path));
if (entity is Directory) {
await Directory(targetPath).create(recursive: true);
await _copyDirectory(entity, Directory(targetPath));
} else if (entity is File) {
await entity.copy(targetPath);
}
}
}
Future<void> _processTemplateFiles(
Directory directory, Map<String, String> replacements) async {
await for (var entity in directory.list(recursive: true)) {
if (entity is File) {
if (path.extension(entity.path) == '.tmpl') {
// Process template file
String content = await entity.readAsString();
for (var entry in replacements.entries) {
content = content.replaceAll('{{${entry.key}}}', entry.value);
}
// Write processed content to new file without .tmpl extension
final newPath = entity.path.replaceAll('.tmpl', '');
await File(newPath).writeAsString(content);
await entity.delete(); // Remove template file
} else {
// Process regular file (only process certain file types)
final ext = path.extension(entity.path);
if (['.dart', '.yaml', '.md', '.json'].contains(ext)) {
String content = await entity.readAsString();
for (var entry in replacements.entries) {
content = content.replaceAll('{{${entry.key}}}', entry.value);
}
await entity.writeAsString(content);
}
}
}
}
}
Future<void> _updatePubspec(File pubspecFile, String projectName) async {
final content = await pubspecFile.readAsString();
final yaml = loadYaml(content);
// Create new pubspec content with updated name
final newContent = content.replaceFirst(
RegExp(r'name:.*'),
'name: $projectName',
);
await pubspecFile.writeAsString(newContent);
}
String _toPascalCase(String input) {
return input
.split(RegExp(r'[_\- ]'))
.map((word) => word[0].toUpperCase() + word.substring(1).toLowerCase())
.join('');
}
String _toCamelCase(String input) {
final pascal = _toPascalCase(input);
return pascal[0].toLowerCase() + pascal.substring(1);
}

121
helpers/create_project.dart Normal file
View file

@ -0,0 +1,121 @@
import 'dart:io';
void main(List<String> args) async {
// Parse command line arguments
String? projectType;
String? category;
String? name;
for (var arg in args) {
final parts = arg.split(':');
if (parts.length == 2) {
switch (parts[0]) {
case 'project_type':
case 'project-type':
projectType = parts[1];
break;
case 'category':
category = parts[1];
break;
case 'name':
name = parts[1];
break;
}
}
}
// Print received arguments for debugging
print('Received arguments:');
print('Project Type: $projectType');
print('Category: $category');
print('Name: $name');
// Validate inputs
if (projectType == null || category == null || name == null) {
print('Error: Missing required arguments');
print(
'Usage: melos run create project_type:dart|flutter category:type name:project_name');
exit(1);
}
if (projectType != 'dart' && projectType != 'flutter') {
print('Error: project_type must be either "dart" or "flutter"');
exit(1);
}
// Determine base directory
final baseDir = projectType == 'flutter' &&
(category == 'app' || category == 'web' || category == 'desktop')
? 'apps'
: 'packages';
// Create project directory
final projectDir = Directory('$baseDir/$name');
if (await projectDir.exists()) {
print('Error: Project directory already exists at ${projectDir.path}');
exit(1);
}
try {
// Ensure the base directory exists
await Directory(baseDir).create(recursive: true);
// Create the project using the appropriate command
final result = await Process.run(
projectType,
[
'create',
if (projectType == 'flutter') ...[
'--org',
'com.example',
'--project-name',
name,
if (category == 'plugin') '--template=plugin',
if (category == 'package') '--template=package',
if (category == 'module') '--template=module',
if (category == 'web') '--platforms=web',
if (category == 'desktop') '--platforms=windows,macos,linux',
] else ...[
if (category == 'package') '--template=package',
if (category == 'console') '--template=console',
if (category == 'server') '--template=server-shelf',
],
projectDir.path,
],
);
if (result.exitCode != 0) {
print('Error creating project:');
print(result.stderr);
exit(1);
}
print('Successfully created $projectType project at ${projectDir.path}');
// Add additional dependencies based on category
if (category == 'server') {
await Process.run('dart', ['pub', 'add', 'shelf_router'],
workingDirectory: projectDir.path);
await Process.run('dart', ['pub', 'add', 'dotenv'],
workingDirectory: projectDir.path);
await Process.run('dart', ['pub', 'add', 'logger'],
workingDirectory: projectDir.path);
}
if (category == 'desktop') {
await Process.run('dart', ['pub', 'add', 'window_manager'],
workingDirectory: projectDir.path);
await Process.run('dart', ['pub', 'add', 'screen_retriever'],
workingDirectory: projectDir.path);
}
// Format the project
await Process.run('dart', ['format', projectDir.path]);
print('Done! 🎉');
print('To get started, cd into ${projectDir.path}');
} catch (e) {
print('Error: $e');
exit(1);
}
}

View file

@ -0,0 +1,53 @@
#!/bin/bash
# Array of extensions to install
extensions=(
"nash.awesome-flutter-snippets" # Dart Data Class Generator
"robert-brunhage.flutter-riverpod-snippets" # Flutter Riverpod Snippets
"usernamehw.errorlens" # Error Lens
"aaron-bond.better-comments" # Better Comments
"plibither8.remove-comments" # Remove Comments
"patbenatar.advanced-new-file" # Advanced New File
"GitHub.copilot" # GitHub Copilot
"dracula-theme.theme-dracula" # Dracula Theme (optional)
"jsayol.firebase-explorer" # Firebase Explorer
"pflannery.vscode-versionlens" # Version Lens
"esentis.flutter-find-unused-assets-and-dart-files" # Find Unused Assets & Dart Files
"humao.rest-client" # REST Client
"rangav.vscode-thunder-client" # Thunder Client
"ritwickdey.liveserver" # Live Server
"Dart-Code.dart-code" # Dart SDK
"Dart-Code.flutter" # Flutter SDK
"ms-vscode.cpptools" # C/C++
"ms-vscode.cpptools-extension-pack" # C/C++ Extension Pack
"ms-vscode.cpptools-themes" # C/C++ Themes
"twxs.cmake " # CMake
"ms-vscode.cmake-tools" # CMake Tools
"ms-vscode.makefile-tools" # Makefile Tools
"saoudrizwan.claude-dev" # Claude Dev
"Continue.continue" # Continue
"DEVSENSE.phptools-vscode" # PHP Tools
"DEVSENSE.composer-php-vscode" # Composer PHP
"DEVSENSE.profiler-php-vscode" # Profiler PHP
"ms-vscode.remote-explorer" # Remote - Containers
"ms-vscode-remote.remote-ssh" # Remote - SSH
"ms-vscode-remote.remote-ssh-edit" # Remote - SSH: Edit
"ms-vscode-remote.remote-containers" # Remote - Containers
"eamodio.gitlens" # GitLens
"DEVSENSE.intelli-php-vscode" # IntelliPHP
"blaugold.melos-code" # Melos
"vscode-icons-team.vscode-icons" # VSCode Icons
"redhat.vscode-yaml" # YAML
"GitHub.vscode-github-actions" # GitHub Actions
"ms-azuretools.vscode-docker" # Docker
"ms-kubernetes-tools.vscode-kubernetes-tools" # Kubernetes
)
# Install each extension
echo "Installing VSCode extensions..."
for extension in "${extensions[@]}"; do
code --install-extension "$extension" --force
echo "Installed: $extension"
done
echo "All extensions have been installed successfully."

View file

@ -0,0 +1,156 @@
import 'dart:io';
import 'package:args/args.dart';
import 'package:path/path.dart' as path;
import 'package:converter/src/extractors/base_extractor.dart';
import 'package:converter/src/extractors/php_extractor.dart';
/// Factory for creating language-specific extractors
class ExtractorFactory {
/// Create an appropriate extractor based on file extension
static LanguageExtractor? createExtractor(String extension) {
switch (extension.toLowerCase()) {
case '.php':
return PhpExtractor();
// TODO: Add more extractors as they're implemented
// case '.py':
// return PythonExtractor();
// case '.ts':
// case '.js':
// return TypeScriptExtractor();
// case '.java':
// return JavaExtractor();
default:
return null;
}
}
}
/// Main contract extractor CLI
class ContractExtractorCLI {
final String sourcePath;
final String outputPath;
final bool verbose;
ContractExtractorCLI({
required this.sourcePath,
required this.outputPath,
this.verbose = false,
});
/// Run the extraction process
Future<void> run() async {
try {
if (await FileSystemEntity.isDirectory(sourcePath)) {
await _processDirectory(sourcePath);
} else if (await FileSystemEntity.isFile(sourcePath)) {
await _processFile(sourcePath);
} else {
throw Exception('Source path does not exist: $sourcePath');
}
} catch (e) {
print('Error: $e');
exit(1);
}
}
/// Process a directory recursively
Future<void> _processDirectory(String dirPath) async {
final dir = Directory(dirPath);
await for (final entity in dir.list(recursive: true)) {
if (entity is File) {
await _processFile(entity.path);
}
}
}
/// Process a single file
Future<void> _processFile(String filePath) async {
final extension = path.extension(filePath);
final extractor = ExtractorFactory.createExtractor(extension);
if (extractor == null) {
if (verbose) {
print('Skipping unsupported file type: $filePath');
}
return;
}
try {
// Calculate relative path to maintain directory structure
final relativePath = path.relative(filePath, from: sourcePath);
final destDir = path.join(outputPath, path.dirname(relativePath));
// Create destination directory
await Directory(destDir).create(recursive: true);
// Extract contract
final contract = await extractor.parseFile(filePath);
final yamlContent = extractor.convertToYaml(contract);
// Write YAML contract
final yamlFile = File(path.join(
destDir,
'${path.basenameWithoutExtension(filePath)}.yaml',
));
await yamlFile.writeAsString(yamlContent);
if (verbose) {
print('Processed: $filePath');
}
} catch (e) {
print('Error processing $filePath: $e');
}
}
}
void main(List<String> arguments) async {
final parser = ArgParser()
..addOption(
'source',
abbr: 's',
help: 'Source file or directory path',
mandatory: true,
)
..addOption(
'output',
abbr: 'o',
help: 'Output directory for YAML contracts',
mandatory: true,
)
..addFlag(
'verbose',
abbr: 'v',
help: 'Enable verbose output',
defaultsTo: false,
)
..addFlag(
'help',
abbr: 'h',
help: 'Show this help message',
negatable: false,
);
try {
final results = parser.parse(arguments);
if (results['help'] as bool) {
print('Usage: dart extract_contracts.dart [options]');
print(parser.usage);
exit(0);
}
final cli = ContractExtractorCLI(
sourcePath: results['source'] as String,
outputPath: results['output'] as String,
verbose: results['verbose'] as bool,
);
await cli.run();
print('Contract extraction completed successfully.');
} catch (e) {
print('Error: $e');
print('\nUsage: dart extract_contracts.dart [options]');
print(parser.usage);
exit(1);
}
}

View file

@ -0,0 +1,108 @@
import 'dart:io';
import 'package:path/path.dart' as path;
void main() async {
// Create a sample PHP file
final samplePhp = '''
<?php
namespace App\\Models;
use Illuminate\\Database\\Eloquent\\Model;
use Illuminate\\Database\\Eloquent\\Factories\\HasFactory;
use App\\Interfaces\\UserInterface;
/**
* User model class.
* Represents a user in the system.
*/
class User extends Model implements UserInterface {
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<string>
*/
protected array \$fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<string>
*/
protected array \$hidden = [
'password',
'remember_token',
];
/**
* Get the user's full name.
*
* @param string \$title Optional title prefix
* @return string
*/
public function getFullName(string \$title = ''): string {
return trim(\$title . ' ' . \$this->name);
}
/**
* Set the user's password.
*
* @param string \$value
* @return void
*/
public function setPasswordAttribute(string \$value): void {
\$this->attributes['password'] = bcrypt(\$value);
}
}
''';
// Create temporary directories
final tempDir = Directory.systemTemp.createTempSync('contract_example');
final sourceDir = Directory(path.join(tempDir.path, 'source'))..createSync();
final outputDir = Directory(path.join(tempDir.path, 'output'))..createSync();
// Write sample PHP file
final phpFile = File(path.join(sourceDir.path, 'User.php'));
await phpFile.writeAsString(samplePhp);
// Run the contract extractor
print('Extracting contracts from ${sourceDir.path}');
print('Output directory: ${outputDir.path}');
final result = await Process.run(
'dart',
[
'run',
'bin/extract_contracts.dart',
'--source',
sourceDir.path,
'--output',
outputDir.path,
'--verbose',
],
);
if (result.exitCode != 0) {
print('Error: ${result.stderr}');
exit(1);
}
// Read and display the generated YAML
final yamlFile = File(path.join(outputDir.path, 'User.yaml'));
if (await yamlFile.exists()) {
print('\nGenerated YAML contract:');
print('------------------------');
print(await yamlFile.readAsString());
} else {
print('Error: YAML file was not generated');
}
// Cleanup
tempDir.deleteSync(recursive: true);
}

View file

@ -0,0 +1,122 @@
import 'dart:io';
import 'package:path/path.dart' as path;
import 'yaml_formatter.dart';
/// Base class for all language extractors
abstract class LanguageExtractor {
/// File extension this extractor handles (e.g., '.php', '.py')
String get fileExtension;
/// Parse a source file and extract its components
Future<Map<String, dynamic>> parseFile(String filePath);
/// Extract class-level documentation
String? extractClassComment(String content);
/// Extract dependencies (imports, use statements, etc.)
List<Map<String, String>> extractDependencies(String content);
/// Extract class properties/fields
List<Map<String, dynamic>> extractProperties(String content);
/// Extract class methods
List<Map<String, dynamic>> extractMethods(String content);
/// Extract implemented interfaces
List<String> extractInterfaces(String content);
/// Extract used traits/mixins
List<String> extractTraits(String content);
/// Convert extracted data to YAML format
String convertToYaml(Map<String, dynamic> data) {
return YamlFormatter.toYaml(data);
}
/// Process a directory of source files
Future<void> processDirectory(String sourceDir, String destDir) async {
final sourceDirectory = Directory(sourceDir);
await for (final entity in sourceDirectory.list(recursive: true)) {
if (entity is! File || !entity.path.endsWith(fileExtension)) continue;
final relativePath = path.relative(entity.path, from: sourceDir);
final destPath = path.join(destDir, path.dirname(relativePath));
await Directory(destPath).create(recursive: true);
final data = await parseFile(entity.path);
final yamlContent = convertToYaml(data);
final yamlFile = File(path.join(
destPath, '${path.basenameWithoutExtension(entity.path)}.yaml'));
await yamlFile.writeAsString(yamlContent);
}
}
/// Parse method parameters from a parameter string
List<Map<String, String>> parseParameters(String paramsStr) {
final params = <Map<String, String>>[];
if (paramsStr.trim().isEmpty) return params;
for (final param in paramsStr.split(',')) {
final parts = param.trim().split('=');
final paramInfo = <String, String>{
'name': parts[0].trim(),
};
if (parts.length > 1) {
paramInfo['default'] = parts[1].trim();
}
params.add(paramInfo);
}
return params;
}
/// Format a comment by removing common comment markers and whitespace
String? formatComment(String? comment) {
if (comment == null || comment.isEmpty) return null;
return comment
.split('\n')
.map((line) => line.trim())
.where((line) => line.isNotEmpty)
.map((line) {
// Remove common comment markers
line = line.replaceAll(RegExp(r'^/\*+|\*+/$'), '');
line = line.replaceAll(RegExp(r'^\s*\*\s*'), '');
line = line.replaceAll(RegExp(r'^//\s*'), '');
return line.trim();
})
.where((line) => line.isNotEmpty)
.join('\n');
}
/// Extract type information from a type string
Map<String, dynamic> extractTypeInfo(String typeStr) {
// Handle nullable types
final isNullable = typeStr.endsWith('?');
if (isNullable) {
typeStr = typeStr.substring(0, typeStr.length - 1);
}
// Handle generics
final genericMatch = RegExp(r'^([\w\d_]+)<(.+)>$').firstMatch(typeStr);
if (genericMatch != null) {
return {
'base_type': genericMatch.group(1),
'generic_params':
genericMatch.group(2)!.split(',').map((t) => t.trim()).toList(),
'nullable': isNullable,
};
}
return {
'type': typeStr,
'nullable': isNullable,
};
}
}

View file

@ -0,0 +1,157 @@
import 'dart:io';
import 'base_extractor.dart';
/// Extracts contract information from PHP source files
class PhpExtractor extends LanguageExtractor {
@override
String get fileExtension => '.php';
@override
Future<Map<String, dynamic>> parseFile(String filePath) async {
final file = File(filePath);
final content = await file.readAsString();
return {
'name': filePath.split('/').last.split('.').first,
'class_comment': extractClassComment(content),
'dependencies': extractDependencies(content),
'properties': extractProperties(content),
'methods': extractMethods(content),
'traits': extractTraits(content),
'interfaces': extractInterfaces(content),
};
}
@override
String? extractClassComment(String content) {
final regex =
RegExp(r'/\*\*(.*?)\*/\s*class', multiLine: true, dotAll: true);
final match = regex.firstMatch(content);
return formatComment(match?.group(1));
}
@override
List<Map<String, String>> extractDependencies(String content) {
final regex = RegExp(r'use\s+([\w\\]+)(?:\s+as\s+(\w+))?;');
final matches = regex.allMatches(content);
return matches.map((match) {
final fullName = match.group(1)!;
final alias = match.group(2);
return {
'name': alias ?? fullName.split('\\').last,
'type': 'class', // Assuming class for now
'source': fullName,
};
}).toList();
}
@override
List<Map<String, dynamic>> extractProperties(String content) {
final regex = RegExp(
r'(?:/\*\*(.*?)\*/\s*)?(public|protected|private)\s+(?:readonly\s+)?(?:static\s+)?(?:[\w|]+\s+)?\$(\w+)(?:\s*=\s*[^;]+)?;',
multiLine: true,
dotAll: true,
);
final matches = regex.allMatches(content);
return matches.map((match) {
return {
'name': match.group(3), // Property name without $
'visibility': match.group(2),
'comment': formatComment(match.group(1)),
};
}).toList();
}
@override
List<Map<String, dynamic>> extractMethods(String content) {
final regex = RegExp(
r'(?:/\*\*(.*?)\*/\s*)?(public|protected|private)\s+(?:static\s+)?function\s+(\w+)\s*\((.*?)\)(?:\s*:\s*(?:[\w|\\]+))?\s*{',
multiLine: true,
dotAll: true,
);
final matches = regex.allMatches(content);
return matches.map((match) {
return {
'name': match.group(3),
'visibility': match.group(2),
'parameters': _parseMethodParameters(match.group(4) ?? ''),
'comment': formatComment(match.group(1)),
};
}).toList();
}
List<Map<String, String>> _parseMethodParameters(String params) {
if (params.trim().isEmpty) return [];
final parameters = <Map<String, String>>[];
final paramList = params.split(',');
for (var param in paramList) {
param = param.trim();
if (param.isEmpty) continue;
final paramInfo = <String, String>{};
// Handle type declaration and parameter name
final typeAndName = param.split(RegExp(r'\$'));
if (typeAndName.length > 1) {
// Has type declaration
final type = typeAndName[0].trim();
if (type.isNotEmpty) {
paramInfo['type'] = type;
}
// Handle parameter name and default value
final nameAndDefault = typeAndName[1].split('=');
paramInfo['name'] = nameAndDefault[0].trim();
if (nameAndDefault.length > 1) {
paramInfo['default'] = nameAndDefault[1].trim();
}
} else {
// No type declaration, just name and possibly default value
final nameAndDefault = param.replaceAll(r'$', '').split('=');
paramInfo['name'] = nameAndDefault[0].trim();
if (nameAndDefault.length > 1) {
paramInfo['default'] = nameAndDefault[1].trim();
}
}
parameters.add(paramInfo);
}
return parameters;
}
@override
List<String> extractTraits(String content) {
final regex = RegExp(r'use\s+([\w\\]+(?:\s*,\s*[\w\\]+)*)\s*;');
final matches = regex.allMatches(content);
final traits = <String>[];
for (final match in matches) {
final traitList = match.group(1)!.split(',');
traits.addAll(traitList.map((t) => t.trim()));
}
return traits;
}
@override
List<String> extractInterfaces(String content) {
final regex = RegExp(r'implements\s+([\w\\]+(?:\s*,\s*[\w\\]+)*)');
final matches = regex.allMatches(content);
final interfaces = <String>[];
for (final match in matches) {
final interfaceList = match.group(1)!.split(',');
interfaces.addAll(interfaceList.map((i) => i.trim()));
}
return interfaces;
}
}

View file

@ -0,0 +1,223 @@
/// Handles YAML formatting with proper comment preservation
class YamlFormatter {
/// Format a value for YAML output
static String format(dynamic value, {int indent = 0}) {
if (value == null) return 'null';
final indentStr = ' ' * indent;
if (value is String) {
if (value.startsWith('#')) {
// Handle comments - preserve only actual comment content
return value
.split('\n')
.map((line) => line.trim())
.where((line) => line.isNotEmpty)
.map((line) => '$indentStr$line')
.join('\n');
}
// Escape special characters and handle multiline strings
if (value.contains('\n') || value.contains('"')) {
return '|\n${value.split('\n').map((line) => '$indentStr ${line.trim()}').join('\n')}';
}
return value.contains(' ') ? '"$value"' : value;
}
if (value is num || value is bool) {
return value.toString();
}
if (value is List) {
if (value.isEmpty) return '[]';
final buffer = StringBuffer('\n');
for (final item in value) {
buffer.writeln(
'$indentStr- ${format(item, indent: indent + 2).trimLeft()}');
}
return buffer.toString().trimRight();
}
if (value is Map) {
if (value.isEmpty) return '{}';
final buffer = StringBuffer('\n');
value.forEach((key, val) {
if (val != null) {
final formattedValue = format(val, indent: indent + 2);
if (formattedValue.contains('\n')) {
buffer.writeln('$indentStr$key:$formattedValue');
} else {
buffer.writeln('$indentStr$key: $formattedValue');
}
// Add extra newline between top-level sections
if (indent == 0) {
buffer.writeln();
}
}
});
return buffer.toString().trimRight();
}
return value.toString();
}
/// Extract the actual documentation from a comment block
static String _extractDocumentation(String comment) {
return comment
.split('\n')
.map((line) => line.trim())
.where((line) => line.isNotEmpty)
.where(
(line) => !line.contains('class ') && !line.contains('function '))
.where((line) => !line.startsWith('@'))
.where((line) => !line.contains('use ') && !line.contains('protected '))
.where((line) => !line.contains('];') && !line.contains('['))
.where((line) => !line.contains("'"))
.where(
(line) => !line.contains('private ') && !line.contains('public '))
.where((line) => !line.contains('\$'))
.map((line) => line.trim())
.where((line) => line.isNotEmpty)
.join('\n');
}
/// Format method documentation
static String formatMethodDoc(Map<String, dynamic> method) {
final buffer = StringBuffer();
// Add main comment
if (method['comment'] != null) {
final mainComment = _extractDocumentation(method['comment'].toString());
if (mainComment.isNotEmpty) {
buffer.writeln(
mainComment.split('\n').map((line) => '# $line').join('\n'));
}
}
// Add parameter documentation
final params = method['parameters'] as List<Map<String, String>>?;
if (params != null && params.isNotEmpty) {
buffer.writeln('# Parameters:');
for (final param in params) {
final name = param['name'];
final type = param['type'] ?? 'mixed';
final defaultValue = param['default'];
if (defaultValue != null) {
buffer.writeln('# $name ($type = $defaultValue)');
} else {
buffer.writeln('# $name ($type)');
}
}
}
return buffer.toString().trimRight();
}
/// Format property documentation
static String formatPropertyDoc(Map<String, dynamic> property) {
final buffer = StringBuffer();
// Add main comment
if (property['comment'] != null) {
final mainComment = _extractDocumentation(property['comment'].toString());
if (mainComment.isNotEmpty) {
buffer.writeln(
mainComment.split('\n').map((line) => '# $line').join('\n'));
}
}
// Add visibility
if (property['visibility'] != null) {
buffer.writeln('# Visibility: ${property["visibility"]}');
}
return buffer.toString().trimRight();
}
/// Convert a contract to YAML format
static String toYaml(Map<String, dynamic> contract) {
final formatted = <String, dynamic>{};
// Format class documentation
if (contract['class_comment'] != null) {
final doc = _extractDocumentation(contract['class_comment'] as String);
if (doc.isNotEmpty) {
formatted['documentation'] =
doc.split('\n').map((line) => '# $line').join('\n');
}
}
// Format dependencies (remove duplicates)
if (contract['dependencies'] != null) {
final deps = contract['dependencies'] as List;
final uniqueDeps = <String, Map<String, String>>{};
for (final dep in deps) {
final source = dep['source'] as String;
if (!uniqueDeps.containsKey(source)) {
uniqueDeps[source] = dep as Map<String, String>;
}
}
formatted['dependencies'] = uniqueDeps.values.toList();
}
// Format properties with documentation
if (contract['properties'] != null) {
formatted['properties'] = (contract['properties'] as List).map((prop) {
final doc = formatPropertyDoc(prop as Map<String, dynamic>);
return {
'name': prop['name'],
'visibility': prop['visibility'],
'documentation': doc,
};
}).toList();
}
// Format methods with documentation
if (contract['methods'] != null) {
formatted['methods'] = (contract['methods'] as List).map((method) {
final doc = formatMethodDoc(method as Map<String, dynamic>);
return {
'name': method['name'],
'visibility': method['visibility'],
'parameters': method['parameters'],
'documentation': doc,
};
}).toList();
}
// Format interfaces (remove duplicates)
if (contract['interfaces'] != null) {
formatted['interfaces'] =
(contract['interfaces'] as List).toSet().toList();
}
// Format traits (remove duplicates and filter out interfaces)
if (contract['traits'] != null) {
final traits = (contract['traits'] as List)
.where((t) {
// Filter out duplicates from dependencies
if (contract['dependencies'] != null) {
final deps = contract['dependencies'] as List;
if (deps.any((d) => d['source'] == t)) {
return false;
}
}
// Filter out interfaces
if (formatted['interfaces'] != null) {
final interfaces = formatted['interfaces'] as List;
if (interfaces.contains(t)) {
return false;
}
}
return true;
})
.toSet()
.toList();
if (traits.isNotEmpty) {
formatted['traits'] = traits;
}
}
return format(formatted);
}
}

View file

@ -0,0 +1,168 @@
import 'name_utils.dart';
import 'type_conversion_utils.dart';
/// Utility class for generating Dart class code
class ClassGeneratorUtils {
/// Generate a constructor for a class
static String generateConstructor(
String className, List<Map<String, dynamic>> properties) {
final buffer = StringBuffer();
// Constructor signature
buffer.writeln(' $className({');
final params = <String>[];
for (final prop in properties) {
final propName = NameUtils.toDartName(prop['name'] as String);
final propType =
TypeConversionUtils.pythonToDartType(prop['type'] as String);
final hasDefault = prop['has_default'] == true;
if (hasDefault) {
params.add(' $propType? $propName,');
} else {
params.add(' required $propType $propName,');
}
}
buffer.writeln(params.join('\n'));
buffer.writeln(' }) {');
// Initialize properties in constructor body
for (final prop in properties) {
final propName = NameUtils.toDartName(prop['name'] as String);
final propType =
TypeConversionUtils.pythonToDartType(prop['type'] as String);
final hasDefault = prop['has_default'] == true;
if (hasDefault) {
final defaultValue = TypeConversionUtils.getDefaultValue(propType);
buffer.writeln(' _$propName = $propName ?? $defaultValue;');
} else {
buffer.writeln(' _$propName = $propName;');
}
}
buffer.writeln(' }');
buffer.writeln();
return buffer.toString();
}
/// Generate property declarations and accessors
static String generateProperties(List<Map<String, dynamic>> properties) {
final buffer = StringBuffer();
for (final prop in properties) {
final propName = NameUtils.toDartName(prop['name'] as String);
final propType =
TypeConversionUtils.pythonToDartType(prop['type'] as String);
buffer.writeln(' late $propType _$propName;');
// Generate getter
buffer.writeln(' $propType get $propName => _$propName;');
// Generate setter if not readonly
final isReadonly = prop['is_readonly'];
if (isReadonly != null && !isReadonly) {
buffer.writeln(' set $propName($propType value) {');
buffer.writeln(' _$propName = value;');
buffer.writeln(' }');
}
buffer.writeln();
}
return buffer.toString();
}
/// Generate a method implementation
static String generateMethod(Map<String, dynamic> method) {
if (method['name'] == '__init__') return '';
final buffer = StringBuffer();
final methodName = NameUtils.toDartName(method['name'] as String);
final returnType =
TypeConversionUtils.pythonToDartType(method['return_type'] as String);
final methodDoc = method['docstring'] as String?;
final isAsync = method['is_async'] == true;
if (methodDoc != null) {
buffer.writeln(' /// ${methodDoc.replaceAll('\n', '\n /// ')}');
}
// Method signature
if (isAsync) {
buffer.write(' Future<$returnType> $methodName(');
} else {
buffer.write(' $returnType $methodName(');
}
// Parameters
final params = method['arguments'] as List?;
if (params != null && params.isNotEmpty) {
final paramStrings = <String>[];
for (final param in params) {
final paramName = NameUtils.toDartName(param['name'] as String);
final paramType =
TypeConversionUtils.pythonToDartType(param['type'] as String);
final isOptional = param['is_optional'] == true;
if (isOptional) {
paramStrings.add('[$paramType $paramName]');
} else {
paramStrings.add('$paramType $paramName');
}
}
buffer.write(paramStrings.join(', '));
}
buffer.write(')');
if (isAsync) buffer.write(' async');
buffer.writeln(' {');
buffer.writeln(' // TODO: Implement $methodName');
if (returnType == 'void') {
buffer.writeln(' throw UnimplementedError();');
} else {
buffer.writeln(' throw UnimplementedError();');
}
buffer.writeln(' }');
buffer.writeln();
return buffer.toString();
}
/// Generate required interface implementations
static String generateRequiredImplementations(
List<String> bases, Map<String, dynamic> classContract) {
final buffer = StringBuffer();
// Generate BaseChain implementations
if (bases.contains('BaseChain')) {
buffer.writeln(' late Map<String, dynamic>? _memory;');
buffer.writeln(' Map<String, dynamic>? get memory => _memory;');
buffer.writeln();
buffer.writeln(' late bool _verbose;');
buffer.writeln(' bool get verbose => _verbose;');
buffer.writeln();
// Constructor with required properties
buffer.writeln(' ${classContract['name']}({');
buffer.writeln(' Map<String, dynamic>? memory,');
buffer.writeln(' bool? verbose,');
buffer.writeln(' }) {');
buffer.writeln(' _memory = memory ?? {};');
buffer.writeln(' _verbose = verbose ?? false;');
buffer.writeln(' }');
buffer.writeln();
// Required methods
buffer.writeln(' @override');
buffer.writeln(' void setMemory(Map<String, dynamic> memory) {');
buffer.writeln(' // TODO: Implement setMemory');
buffer.writeln(' throw UnimplementedError();');
buffer.writeln(' }');
buffer.writeln();
}
return buffer.toString();
}
}

View file

@ -0,0 +1,40 @@
/// Utility functions for constructor generation
class ConstructorUtils {
/// Generate constructor parameter declarations
static String generateParameters(List<Map<String, dynamic>> properties) {
final buffer = StringBuffer();
for (final prop in properties) {
final propName = prop['name'] as String;
final propType = prop['type'] as String;
final hasDefault = prop['has_default'] == true;
if (hasDefault) {
buffer.writeln(' $propType? $propName,');
} else {
buffer.writeln(' required $propType $propName,');
}
}
return buffer.toString();
}
/// Generate constructor initialization statements
static String generateInitializers(List<Map<String, dynamic>> properties) {
final buffer = StringBuffer();
for (final prop in properties) {
final propName = prop['name'] as String;
final hasDefault = prop['has_default'] == true;
if (hasDefault) {
buffer.writeln(
' _$propName = $propName ?? false;'); // TODO: Better default values
} else {
buffer.writeln(' _$propName = $propName;');
}
}
return buffer.toString();
}
/// Check if a method is a constructor (__init__)
static bool isConstructor(Map<String, dynamic> method) {
return method['name'] == '__init__';
}
}

View file

@ -0,0 +1,23 @@
/// Utility functions for name conversions
class NameUtils {
/// Convert Python method/property name to Dart style
static String toDartName(String pythonName) {
// Handle special Python method names
if (pythonName.startsWith('__') && pythonName.endsWith('__')) {
final name = pythonName.substring(2, pythonName.length - 2);
if (name == 'init') return 'new';
return name;
}
// Convert snake_case to camelCase
final parts = pythonName.split('_');
if (parts.isEmpty) return pythonName;
return parts.first +
parts
.skip(1)
.where((p) => p.isNotEmpty)
.map((p) => p[0].toUpperCase() + p.substring(1))
.join('');
}
}

View file

@ -0,0 +1,87 @@
/// Utility class for converting Python types to Dart types
class TypeConversionUtils {
/// Convert a Python type string to its Dart equivalent
static String pythonToDartType(String pythonType) {
final typeMap = {
'str': 'String',
'int': 'int',
'float': 'double',
'bool': 'bool',
'List': 'List',
'Dict': 'Map',
'dict': 'Map<String, dynamic>',
'Any': 'dynamic',
'None': 'void',
'Optional': 'dynamic',
'Union': 'dynamic',
'Callable': 'Function',
};
// Handle generic types
if (pythonType.contains('[')) {
final match = RegExp(r'(\w+)\[(.*)\]').firstMatch(pythonType);
if (match != null) {
final baseType = match.group(1)!;
final genericType = match.group(2)!;
if (baseType == 'List') {
return 'List<${pythonToDartType(genericType)}>';
} else if (baseType == 'Dict' || baseType == 'dict') {
final types = genericType.split(',');
if (types.length == 2) {
return 'Map<${pythonToDartType(types[0].trim())}, ${pythonToDartType(types[1].trim())}>';
}
return 'Map<String, dynamic>';
} else if (baseType == 'Optional') {
final innerType = pythonToDartType(genericType);
if (innerType == 'Map<String, dynamic>') {
return 'Map<String, dynamic>?';
}
return '${innerType}?';
}
}
}
// Handle raw types
if (pythonType == 'dict') {
return 'Map<String, dynamic>';
} else if (pythonType == 'None') {
return 'void';
}
return typeMap[pythonType] ?? pythonType;
}
/// Get a default value for a Dart type
static String getDefaultValue(String dartType) {
switch (dartType) {
case 'bool':
case 'bool?':
return 'false';
case 'int':
case 'int?':
return '0';
case 'double':
case 'double?':
return '0.0';
case 'String':
case 'String?':
return "''";
case 'Map<String, dynamic>':
case 'Map<String, dynamic>?':
return '{}';
case 'List':
case 'List?':
return '[]';
default:
if (dartType.startsWith('List<')) {
return '[]';
} else if (dartType.startsWith('Map<')) {
return '{}';
} else if (dartType.endsWith('?')) {
return 'null';
}
return 'null';
}
}
}

View file

@ -0,0 +1,20 @@
/// Utility functions for type casting
class TypeUtils {
/// Cast a List<dynamic> to List<Map<String, dynamic>>
static List<Map<String, dynamic>> castToMapList(List<dynamic>? list) {
if (list == null) return [];
return list.map((item) => item as Map<String, dynamic>).toList();
}
/// Cast a dynamic value to Map<String, dynamic>
static Map<String, dynamic> castToMap(dynamic value) {
if (value == null) return {};
return value as Map<String, dynamic>;
}
/// Cast a List<dynamic> to List<String>
static List<String> castToStringList(List<dynamic>? list) {
if (list == null) return [];
return list.map((item) => item.toString()).toList();
}
}

View file

@ -0,0 +1,36 @@
import 'package:yaml/yaml.dart';
/// Utility class for handling YAML conversions
class YamlUtils {
/// Convert YamlMap to regular Map recursively
static Map<String, dynamic> convertYamlToMap(YamlMap yamlMap) {
return Map<String, dynamic>.fromEntries(
yamlMap.entries.map((entry) {
if (entry.value is YamlMap) {
return MapEntry(
entry.key.toString(),
convertYamlToMap(entry.value as YamlMap),
);
} else if (entry.value is YamlList) {
return MapEntry(
entry.key.toString(),
convertYamlList(entry.value as YamlList),
);
}
return MapEntry(entry.key.toString(), entry.value);
}),
);
}
/// Convert YamlList to regular List recursively
static List<dynamic> convertYamlList(YamlList yamlList) {
return yamlList.map((item) {
if (item is YamlMap) {
return convertYamlToMap(item);
} else if (item is YamlList) {
return convertYamlList(item);
}
return item;
}).toList();
}
}

View file

@ -0,0 +1,402 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77"
url: "https://pub.dev"
source: hosted
version: "73.0.0"
_macros:
dependency: transitive
description: dart
source: sdk
version: "0.3.2"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a"
url: "https://pub.dev"
source: hosted
version: "6.8.0"
args:
dependency: "direct main"
description:
name: args
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
url: "https://pub.dev"
source: hosted
version: "2.6.0"
async:
dependency: transitive
description:
name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
url: "https://pub.dev"
source: hosted
version: "2.12.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
coverage:
dependency: transitive
description:
name: coverage
sha256: "88b0fddbe4c92910fefc09cc0248f5e7f0cd23e450ded4c28f16ab8ee8f83268"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev"
source: hosted
version: "3.0.6"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "4.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360"
url: "https://pub.dev"
source: hosted
version: "4.1.1"
io:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
js:
dependency: transitive
description:
name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
url: "https://pub.dev"
source: hosted
version: "0.7.1"
lints:
dependency: "direct dev"
description:
name: lints
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
logging:
dependency: transitive
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev"
source: hosted
version: "1.3.0"
macros:
dependency: transitive
description:
name: macros
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
url: "https://pub.dev"
source: hosted
version: "0.1.2-main.4"
matcher:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
meta:
dependency: transitive
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.16.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
package_config:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
path:
dependency: "direct main"
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
pool:
dependency: transitive
description:
name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
shelf:
dependency: transitive
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.2"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.dev"
source: hosted
version: "1.1.3"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
url: "https://pub.dev"
source: hosted
version: "2.1.2"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
url: "https://pub.dev"
source: hosted
version: "0.10.12"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test:
dependency: "direct dev"
description:
name: test
sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f"
url: "https://pub.dev"
source: hosted
version: "1.25.8"
test_api:
dependency: transitive
description:
name: test_api
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.3"
test_core:
dependency: transitive
description:
name: test_core
sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d"
url: "https://pub.dev"
source: hosted
version: "0.6.5"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
url: "https://pub.dev"
source: hosted
version: "14.3.1"
watcher:
dependency: transitive
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
url: "https://pub.dev"
source: hosted
version: "0.1.6"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
yaml:
dependency: "direct main"
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.5.0 <4.0.0"

View file

@ -0,0 +1,15 @@
name: converter
description: A Dart implementation of LangChain, providing tools and utilities for building applications powered by large language models (LLMs).
version: 0.1.0
environment:
sdk: '>=3.0.0 <4.0.0'
dependencies:
yaml: ^3.1.2
path: ^1.8.3
args: ^2.4.2
dev_dependencies:
lints: ^2.1.1
test: ^1.24.6

View file

@ -0,0 +1,95 @@
import 'package:test/test.dart';
import '../tools/generate_dart_code.dart';
void main() {
group('Class Generation', () {
test('generates class with interface implementations', () {
final classContract = {
'name': 'SimpleChain',
'docstring': 'A simple implementation of a chain.',
'bases': ['BaseChain'],
'methods': [
{
'name': 'run',
'return_type': 'dict',
'arguments': [
{
'name': 'inputs',
'type': 'dict',
'is_optional': false,
}
],
'docstring': 'Execute the chain logic.',
}
],
};
final code = generateClass(classContract);
// Should include BaseChain implementations
expect(code, contains('late Map<String, dynamic>? _memory;'));
expect(code, contains('Map<String, dynamic>? get memory => _memory;'));
expect(code, contains('late bool _verbose;'));
expect(code, contains('bool get verbose => _verbose;'));
// Should include constructor with required properties
expect(code, contains('SimpleChain({'));
expect(code, contains('Map<String, dynamic>? memory,'));
expect(code, contains('bool? verbose,'));
expect(code, contains('_memory = memory ?? {};'));
expect(code, contains('_verbose = verbose ?? false;'));
// Should include required method implementations
expect(code, contains('@override'));
expect(code, contains('void setMemory(Map<String, dynamic> memory)'));
// Should include additional methods
expect(code, contains('Map<String, dynamic> run('));
expect(code, contains('Map<String, dynamic> inputs'));
expect(code, contains('/// Execute the chain logic.'));
});
test('generates class with own properties and methods', () {
final classContract = {
'name': 'CustomClass',
'docstring': 'A custom class.',
'properties': [
{
'name': 'model_name',
'type': 'String',
'has_default': false,
}
],
'methods': [
{
'name': 'process',
'return_type': 'String',
'arguments': [
{
'name': 'input',
'type': 'String',
'is_optional': false,
}
],
'docstring': 'Process input.',
}
],
};
final code = generateClass(classContract);
// Should include properties
expect(code, contains('late String _modelName;'));
expect(code, contains('String get modelName => _modelName;'));
// Should include constructor
expect(code, contains('CustomClass({'));
expect(code, contains('required String modelName'));
expect(code, contains('_modelName = modelName;'));
// Should include methods
expect(code, contains('String process(String input)'));
expect(code, contains('/// Process input.'));
});
});
}

View file

@ -0,0 +1,84 @@
import 'package:test/test.dart';
import '../tools/generate_dart_code.dart';
import '../lib/src/utils/class_generator_utils.dart';
void main() {
group('Code Generator Integration', () {
test('generates complete class with properties and methods', () {
final classContract = {
'name': 'TestModel',
'docstring': 'A test model implementation.',
'bases': ['BaseModel'],
'properties': [
{
'name': 'model_name',
'type': 'String',
'has_default': false,
},
{
'name': 'is_loaded',
'type': 'bool',
'has_default': true,
}
],
'methods': [
{
'name': '__init__',
'return_type': 'None',
'arguments': [
{
'name': 'model_name',
'type': 'String',
'is_optional': false,
'has_default': false,
}
],
'docstring': 'Initialize the model.',
},
{
'name': 'process_input',
'return_type': 'String',
'arguments': [
{
'name': 'input_text',
'type': 'String',
'is_optional': false,
'has_default': false,
}
],
'docstring': 'Process input text.',
'is_async': true,
}
],
};
final code = generateClass(classContract);
// Class definition
expect(code, contains('class TestModel implements BaseModel {'));
expect(code, contains('/// A test model implementation.'));
// Properties
expect(code, contains('late String _modelName;'));
expect(code, contains('String get modelName => _modelName;'));
expect(code, contains('late bool _isLoaded;'));
expect(code, contains('bool get isLoaded => _isLoaded;'));
// Constructor
expect(code, contains('TestModel({'));
expect(code, contains('required String modelName,'));
expect(code, contains('bool? isLoaded,'));
expect(code, contains('_modelName = modelName;'));
expect(code, contains('_isLoaded = isLoaded ?? false;'));
// Methods
expect(code,
contains('Future<String> processInput(String inputText) async {'));
expect(code, contains('/// Process input text.'));
// No __init__ method
expect(code, isNot(contains('__init__')));
expect(code, isNot(contains('void new(')));
});
});
}

View file

@ -0,0 +1,63 @@
import 'package:test/test.dart';
import '../tools/generate_dart_code.dart';
void main() {
group('Code Generator Name Handling', () {
test('converts Python method names to Dart style in interfaces', () {
final interface = {
'name': 'TestInterface',
'docstring': 'Test interface.',
'methods': [
{
'name': 'get_model_name',
'return_type': 'str',
'arguments': [],
'docstring': 'Get model name.',
},
{
'name': '__init__',
'return_type': 'None',
'arguments': [
{
'name': 'model_path',
'type': 'str',
'is_optional': false,
'has_default': false,
}
],
'docstring': 'Initialize.',
}
],
'properties': [],
};
final code = generateInterface(interface);
expect(code, contains('String getModelName();'));
expect(code, contains('void new(String modelPath);'));
});
test('converts Python property names to Dart style in classes', () {
final classContract = {
'name': 'TestClass',
'docstring': 'Test class.',
'properties': [
{
'name': 'model_name',
'type': 'str',
'has_default': false,
},
{
'name': 'is_initialized',
'type': 'bool',
'has_default': true,
}
],
'methods': [],
};
final code = generateClass(classContract);
expect(code, contains('String get modelName'));
expect(code, contains('bool get isInitialized'));
});
});
}

View file

@ -0,0 +1,83 @@
import 'package:test/test.dart';
import '../tools/generate_dart_code.dart';
void main() {
group('Code Generator', () {
test('generates constructor correctly', () {
final classContract = {
'name': 'TestClass',
'docstring': 'Test class.',
'properties': [
{
'name': 'name',
'type': 'String',
'has_default': false,
},
{
'name': 'is_ready',
'type': 'bool',
'has_default': true,
}
],
};
final code = generateClass(classContract);
expect(code, contains('TestClass({'));
expect(code, contains('required String name,'));
expect(code, contains('bool? isReady,'));
expect(code, contains('_name = name;'));
expect(code, contains('_isReady = isReady ?? false;'));
});
test('handles async methods correctly', () {
final classContract = {
'name': 'TestClass',
'docstring': 'Test class.',
'methods': [
{
'name': 'process',
'return_type': 'String',
'arguments': [
{
'name': 'input',
'type': 'String',
'is_optional': false,
}
],
'docstring': 'Process input.',
'is_async': true,
}
],
};
final code = generateClass(classContract);
expect(code, contains('Future<String> process(String input) async {'));
expect(code, contains('/// Process input.'));
});
test('initializes properties in constructor', () {
final classContract = {
'name': 'TestClass',
'docstring': 'Test class.',
'properties': [
{
'name': 'name',
'type': 'String',
'has_default': false,
},
{
'name': 'is_ready',
'type': 'bool',
'has_default': true,
}
],
};
final code = generateClass(classContract);
expect(code, contains('late String _name;'));
expect(code, contains('late bool _isReady;'));
expect(code, contains('_name = name;'));
expect(code, contains('_isReady = isReady ?? false;'));
});
});
}

View file

@ -0,0 +1,181 @@
import 'package:test/test.dart';
import '../../lib/src/extractors/php_extractor.dart';
void main() {
group('PhpExtractor', () {
final extractor = PhpExtractor();
test('extracts class comment', () {
const phpCode = '''
/**
* User entity class.
* Represents a user in the system.
*/
class User {
}
''';
final comment = extractor.extractClassComment(phpCode);
expect(comment, contains('User entity class'));
expect(comment, contains('Represents a user in the system'));
});
test('extracts dependencies', () {
const phpCode = '''
use App\\Models\\User;
use Illuminate\\Support\\Str as StringHelper;
use App\\Interfaces\\UserInterface;
''';
final deps = extractor.extractDependencies(phpCode);
expect(deps, hasLength(3));
expect(deps[0]['name'], equals('User'));
expect(deps[1]['name'], equals('StringHelper'));
expect(deps[2]['name'], equals('UserInterface'));
expect(deps[1]['source'], equals('Illuminate\\Support\\Str'));
});
test('extracts properties', () {
const phpCode = '''
class User {
/**
* The user's name.
*/
private string \$name;
/**
* The user's email.
*/
protected string \$email;
/**
* Is the user active?
*/
public bool \$isActive = false;
}
''';
final props = extractor.extractProperties(phpCode);
expect(props, hasLength(3));
expect(props[0]['name'], equals('name'));
expect(props[0]['visibility'], equals('private'));
expect(props[0]['comment'], contains("The user's name"));
expect(props[1]['name'], equals('email'));
expect(props[1]['visibility'], equals('protected'));
expect(props[2]['name'], equals('isActive'));
expect(props[2]['visibility'], equals('public'));
});
test('extracts methods', () {
const phpCode = '''
class User {
/**
* Get the user's full name.
* @param string \$title Optional title
* @return string
*/
public function getFullName(string \$title = '') {
return \$title . ' ' . \$this->name;
}
/**
* Set the user's email address.
*/
protected function setEmail(string \$email) {
\$this->email = \$email;
}
}
''';
final methods = extractor.extractMethods(phpCode);
expect(methods, hasLength(2));
expect(methods[0]['name'], equals('getFullName'));
expect(methods[0]['visibility'], equals('public'));
expect(methods[0]['parameters'], hasLength(1));
expect(methods[0]['parameters'][0]['name'], equals('title'));
expect(methods[0]['parameters'][0]['default'], equals("''"));
expect(methods[0]['comment'], contains("Get the user's full name"));
expect(methods[1]['name'], equals('setEmail'));
expect(methods[1]['visibility'], equals('protected'));
expect(methods[1]['parameters'], hasLength(1));
expect(methods[1]['parameters'][0]['name'], equals('email'));
});
test('extracts interfaces', () {
const phpCode = '''
class User implements UserInterface, Authenticatable {
}
''';
final interfaces = extractor.extractInterfaces(phpCode);
expect(interfaces, hasLength(2));
expect(interfaces[0], equals('UserInterface'));
expect(interfaces[1], equals('Authenticatable'));
});
test('extracts traits', () {
const phpCode = '''
class User {
use HasFactory, Notifiable;
}
''';
final traits = extractor.extractTraits(phpCode);
expect(traits, hasLength(2));
expect(traits[0], equals('HasFactory'));
expect(traits[1], equals('Notifiable'));
});
test('generates valid YAML output', () {
const phpCode = '''
/**
* User entity class.
*/
class User implements UserInterface {
use HasFactory;
/**
* The user's name.
*/
private string \$name;
/**
* Get the user's name.
*/
public function getName(): string {
return \$this->name;
}
}
''';
final contract = {
'name': 'User',
'class_comment': extractor.extractClassComment(phpCode),
'dependencies': extractor.extractDependencies(phpCode),
'properties': extractor.extractProperties(phpCode),
'methods': extractor.extractMethods(phpCode),
'traits': extractor.extractTraits(phpCode),
'interfaces': extractor.extractInterfaces(phpCode),
};
final yaml = extractor.convertToYaml(contract);
// Check required sections
expect(yaml, contains('documentation:'));
expect(yaml, contains('properties:'));
expect(yaml, contains('methods:'));
expect(yaml, contains('interfaces:'));
// Check content
expect(yaml, contains('User entity class'));
expect(yaml, contains('name: name'));
expect(yaml, contains('visibility: private'));
expect(yaml, contains('name: getName'));
expect(yaml, contains('visibility: public'));
expect(yaml, contains('UserInterface'));
// Verify formatting
expect(yaml, isNot(contains('class User')));
expect(yaml, isNot(contains('function')));
expect(yaml, isNot(contains('private string')));
});
});
}

View file

@ -0,0 +1,112 @@
interfaces:
-
name: "LLMProtocol"
bases:
- Protocol
methods:
-
name: "generate"
arguments:
-
name: "prompts"
type: "List[str]"
is_optional: false
has_default: false
return_type: "List[str]"
docstring: "Generate completions for the prompts."
decorators:
-
name: "abstractmethod"
is_abstract: true
-
name: "model_name"
arguments:
return_type: "str"
docstring: "Get the model name."
decorators:
-
name: "property"
-
name: "abstractmethod"
is_abstract: true
properties:
docstring: "Protocol for language models."
decorators:
is_interface: true
classes:
-
name: "BaseChain"
bases:
- ABC
methods:
-
name: "run"
arguments:
-
name: "inputs"
type: "dict"
is_optional: false
has_default: false
return_type: "dict"
docstring: "Run the chain on the inputs."
decorators:
-
name: "abstractmethod"
is_abstract: true
-
name: "set_memory"
arguments:
-
name: "memory"
type: "dict"
is_optional: false
has_default: false
return_type: "None"
docstring: "Set the memory for the chain."
decorators:
is_abstract: false
properties:
-
name: "memory"
type: "Optional[dict]"
has_default: true
-
name: "verbose"
type: "bool"
has_default: true
docstring: "Base class for chains."
decorators:
is_interface: false
-
name: "SimpleChain"
bases:
- BaseChain
methods:
-
name: "__init__"
arguments:
-
name: "llm"
type: "LLMProtocol"
is_optional: false
has_default: false
return_type: "None"
docstring: "Initialize the chain."
decorators:
is_abstract: false
-
name: "run"
arguments:
-
name: "inputs"
type: "dict"
is_optional: false
has_default: false
return_type: "dict"
docstring: "Execute the chain logic."
decorators:
is_abstract: false
properties:
docstring: "A simple implementation of a chain."
decorators:
is_interface: false

View file

@ -0,0 +1,46 @@
from typing import List, Optional, Protocol
from abc import ABC, abstractmethod
class LLMProtocol(Protocol):
"""Protocol for language models."""
@abstractmethod
async def generate(self, prompts: List[str], **kwargs) -> List[str]:
"""Generate completions for the prompts."""
pass
@property
@abstractmethod
def model_name(self) -> str:
"""Get the model name."""
pass
class BaseChain(ABC):
"""Base class for chains."""
memory: Optional[dict] = None
verbose: bool = False
@abstractmethod
async def run(self, inputs: dict) -> dict:
"""Run the chain on the inputs."""
pass
def set_memory(self, memory: dict) -> None:
"""Set the memory for the chain."""
self.memory = memory
class SimpleChain(BaseChain):
"""A simple implementation of a chain."""
def __init__(self, llm: LLMProtocol):
"""Initialize the chain."""
self.llm = llm
self.history: List[str] = []
async def run(self, inputs: dict) -> dict:
"""Execute the chain logic."""
prompt = inputs.get("prompt", "")
result = await self.llm.generate([prompt])
self.history.append(result[0])
return {"output": result[0]}

View file

@ -0,0 +1,91 @@
import 'dart:io';
import 'package:test/test.dart';
import '../tools/python_parser.dart';
void main() {
group('PythonParser', () {
test('parses interface correctly', () async {
final file = File('test/fixtures/sample.py');
final classes = await PythonParser.parseFile(file);
final interface = classes.firstWhere((c) => c.isInterface);
expect(interface.name, equals('LLMProtocol'));
expect(interface.docstring, equals('Protocol for language models.'));
// Test generate method
final generateMethod =
interface.methods.firstWhere((m) => m.name == 'generate');
expect(generateMethod.isAsync, isTrue);
expect(generateMethod.isAbstract, isTrue);
expect(generateMethod.docstring,
equals('Generate completions for the prompts.'));
expect(generateMethod.parameters.length, equals(1));
expect(generateMethod.parameters.first.name, equals('prompts'));
expect(generateMethod.parameters.first.type, equals('List[str]'));
expect(generateMethod.returnType, equals('List[str]'));
// Test model_name property
final modelNameMethod =
interface.methods.firstWhere((m) => m.name == 'model_name');
expect(modelNameMethod.isProperty, isTrue);
expect(modelNameMethod.isAbstract, isTrue);
expect(modelNameMethod.docstring, equals('Get the model name.'));
expect(modelNameMethod.parameters.isEmpty, isTrue);
expect(modelNameMethod.returnType, equals('str'));
});
test('parses abstract class correctly', () async {
final file = File('test/fixtures/sample.py');
final classes = await PythonParser.parseFile(file);
final abstractClass = classes.firstWhere((c) => c.name == 'BaseChain');
expect(abstractClass.docstring, equals('Base class for chains.'));
// Test properties
expect(abstractClass.properties.length, equals(2));
final memoryProp =
abstractClass.properties.firstWhere((p) => p.name == 'memory');
expect(memoryProp.type, equals('Optional[dict]'));
expect(memoryProp.hasDefault, isTrue);
// Test run method
final runMethod =
abstractClass.methods.firstWhere((m) => m.name == 'run');
expect(runMethod.isAsync, isTrue);
expect(runMethod.isAbstract, isTrue);
expect(runMethod.docstring, equals('Run the chain on the inputs.'));
expect(runMethod.parameters.length, equals(1));
expect(runMethod.parameters.first.name, equals('inputs'));
expect(runMethod.parameters.first.type, equals('dict'));
expect(runMethod.returnType, equals('dict'));
});
test('parses concrete class correctly', () async {
final file = File('test/fixtures/sample.py');
final classes = await PythonParser.parseFile(file);
final concreteClass = classes.firstWhere((c) => c.name == 'SimpleChain');
expect(concreteClass.docstring,
equals('A simple implementation of a chain.'));
// Test constructor
final constructor =
concreteClass.methods.firstWhere((m) => m.name == '__init__');
expect(constructor.docstring, equals('Initialize the chain.'));
expect(constructor.parameters.length, equals(1));
expect(constructor.parameters.first.name, equals('llm'));
expect(constructor.parameters.first.type, equals('LLMProtocol'));
// Test run method
final runMethod =
concreteClass.methods.firstWhere((m) => m.name == 'run');
expect(runMethod.isAsync, isTrue);
expect(runMethod.isAbstract, isFalse);
expect(runMethod.docstring, equals('Execute the chain logic.'));
expect(runMethod.parameters.length, equals(1));
expect(runMethod.parameters.first.name, equals('inputs'));
expect(runMethod.parameters.first.type, equals('dict'));
expect(runMethod.returnType, equals('dict'));
});
});
}

View file

@ -0,0 +1,85 @@
import 'package:test/test.dart';
import '../../lib/src/utils/class_generator_utils.dart';
void main() {
group('ClassGeneratorUtils', () {
test('generates constructor with property initialization', () {
final properties = [
{
'name': 'model_name',
'type': 'String',
'has_default': false,
},
{
'name': 'is_ready',
'type': 'bool',
'has_default': true,
}
];
final code =
ClassGeneratorUtils.generateConstructor('TestClass', properties);
expect(code, contains('TestClass({'));
expect(code, contains('required String modelName,'));
expect(code, contains('bool? isReady,'));
expect(code, contains('_modelName = modelName;'));
expect(code, contains('_isReady = isReady ?? false;'));
});
test('generates properties with getters and setters', () {
final properties = [
{
'name': 'model_name',
'type': 'String',
'is_readonly': true,
},
{
'name': 'is_ready',
'type': 'bool',
'is_readonly': false,
}
];
final code = ClassGeneratorUtils.generateProperties(properties);
expect(code, contains('late String _modelName;'));
expect(code, contains('String get modelName => _modelName;'));
expect(code, contains('late bool _isReady;'));
expect(code, contains('bool get isReady => _isReady;'));
expect(code, contains('set isReady(bool value)'));
expect(code, isNot(contains('set modelName')));
});
test('generates async method correctly', () {
final method = {
'name': 'process_input',
'return_type': 'String',
'arguments': [
{
'name': 'input',
'type': 'String',
'is_optional': false,
}
],
'docstring': 'Process the input.',
'is_async': true,
};
final code = ClassGeneratorUtils.generateMethod(method);
expect(code, contains('Future<String> processInput('));
expect(code, contains('String input'));
expect(code, contains('async {'));
expect(code, contains('/// Process the input.'));
});
test('skips generating constructor method', () {
final method = {
'name': '__init__',
'return_type': 'void',
'arguments': [],
};
final code = ClassGeneratorUtils.generateMethod(method);
expect(code, isEmpty);
});
});
}

View file

@ -0,0 +1,68 @@
import 'package:test/test.dart';
import '../../lib/src/utils/constructor_utils.dart';
void main() {
group('ConstructorUtils', () {
test('generates required parameters for non-default properties', () {
final properties = [
{
'name': 'model_name',
'type': 'String',
'has_default': false,
}
];
final params = ConstructorUtils.generateParameters(properties);
expect(params, contains('required String model_name'));
});
test('generates optional parameters for default properties', () {
final properties = [
{
'name': 'is_ready',
'type': 'bool',
'has_default': true,
}
];
final params = ConstructorUtils.generateParameters(properties);
expect(params, contains('bool? is_ready'));
});
test('generates property initializers', () {
final properties = [
{
'name': 'model_name',
'type': 'String',
'has_default': false,
},
{
'name': 'is_ready',
'type': 'bool',
'has_default': true,
}
];
final inits = ConstructorUtils.generateInitializers(properties);
expect(inits, contains('_model_name = model_name;'));
expect(inits, contains('_is_ready = is_ready ?? false;'));
});
test('identifies constructor methods', () {
final initMethod = {
'name': '__init__',
'return_type': 'None',
'arguments': [],
};
final regularMethod = {
'name': 'process',
'return_type': 'String',
'arguments': [],
};
expect(ConstructorUtils.isConstructor(initMethod), isTrue);
expect(ConstructorUtils.isConstructor(regularMethod), isFalse);
});
});
}

View file

@ -0,0 +1,84 @@
import 'package:test/test.dart';
import '../../lib/src/utils/class_generator_utils.dart';
void main() {
group('Interface Implementation Generation', () {
test('generates required BaseChain implementations', () {
final bases = ['BaseChain'];
final classContract = {
'name': 'SimpleChain',
'docstring': 'A simple implementation of a chain.',
'methods': [
{
'name': 'run',
'return_type': 'dict',
'arguments': [
{
'name': 'inputs',
'type': 'dict',
'is_optional': false,
}
],
'docstring': 'Execute the chain logic.',
}
],
};
final code = ClassGeneratorUtils.generateRequiredImplementations(
bases, classContract);
// Should include memory property
expect(code, contains('late Map<String, dynamic>? _memory;'));
expect(code, contains('Map<String, dynamic>? get memory => _memory;'));
// Should include verbose property
expect(code, contains('late bool _verbose;'));
expect(code, contains('bool get verbose => _verbose;'));
// Should include constructor with required properties
expect(code, contains('SimpleChain({'));
expect(code, contains('Map<String, dynamic>? memory,'));
expect(code, contains('bool? verbose,'));
expect(code, contains('_memory = memory ?? {};'));
expect(code, contains('_verbose = verbose ?? false;'));
// Should include required method implementations
expect(code, contains('@override'));
expect(code, contains('void setMemory(Map<String, dynamic> memory)'));
});
test('handles multiple interface implementations', () {
final bases = ['BaseChain', 'Serializable'];
final classContract = {
'name': 'SimpleChain',
'docstring': 'A simple implementation of a chain.',
'methods': [],
};
final code = ClassGeneratorUtils.generateRequiredImplementations(
bases, classContract);
// Should include BaseChain implementations
expect(code, contains('Map<String, dynamic>? get memory'));
expect(code, contains('bool get verbose'));
// Should include constructor with all required properties
expect(code, contains('SimpleChain({'));
expect(code, contains('Map<String, dynamic>? memory,'));
expect(code, contains('bool? verbose,'));
});
test('handles no interface implementations', () {
final bases = <String>[];
final classContract = {
'name': 'SimpleClass',
'docstring': 'A simple class.',
'methods': [],
};
final code = ClassGeneratorUtils.generateRequiredImplementations(
bases, classContract);
expect(code, isEmpty);
});
});
}

View file

@ -0,0 +1,37 @@
import 'package:test/test.dart';
import '../../lib/src/utils/name_utils.dart';
void main() {
group('NameUtils', () {
test('converts snake_case to camelCase', () {
expect(NameUtils.toDartName('hello_world'), equals('helloWorld'));
expect(NameUtils.toDartName('get_model_name'), equals('getModelName'));
expect(NameUtils.toDartName('set_memory'), equals('setMemory'));
});
test('handles single word correctly', () {
expect(NameUtils.toDartName('hello'), equals('hello'));
expect(NameUtils.toDartName('test'), equals('test'));
});
test('preserves existing camelCase', () {
expect(NameUtils.toDartName('helloWorld'), equals('helloWorld'));
expect(NameUtils.toDartName('getModelName'), equals('getModelName'));
});
test('handles empty string', () {
expect(NameUtils.toDartName(''), equals(''));
});
test('handles special method names', () {
expect(NameUtils.toDartName('__init__'), equals('new'));
expect(NameUtils.toDartName('__str__'), equals('str'));
expect(NameUtils.toDartName('__repr__'), equals('repr'));
});
test('handles consecutive underscores', () {
expect(NameUtils.toDartName('hello__world'), equals('helloWorld'));
expect(NameUtils.toDartName('test___name'), equals('testName'));
});
});
}

View file

@ -0,0 +1,90 @@
import 'package:test/test.dart';
import '../../lib/src/utils/type_conversion_utils.dart';
void main() {
group('TypeConversionUtils', () {
group('pythonToDartType', () {
test('converts basic Python types to Dart types', () {
expect(TypeConversionUtils.pythonToDartType('str'), equals('String'));
expect(TypeConversionUtils.pythonToDartType('int'), equals('int'));
expect(TypeConversionUtils.pythonToDartType('bool'), equals('bool'));
expect(TypeConversionUtils.pythonToDartType('None'), equals('void'));
expect(TypeConversionUtils.pythonToDartType('dict'),
equals('Map<String, dynamic>'));
});
test('converts List types correctly', () {
expect(TypeConversionUtils.pythonToDartType('List[str]'),
equals('List<String>'));
expect(TypeConversionUtils.pythonToDartType('List[int]'),
equals('List<int>'));
expect(TypeConversionUtils.pythonToDartType('List[dict]'),
equals('List<Map<String, dynamic>>'));
});
test('converts Dict types correctly', () {
expect(TypeConversionUtils.pythonToDartType('Dict[str, Any]'),
equals('Map<String, dynamic>'));
expect(TypeConversionUtils.pythonToDartType('Dict[str, int]'),
equals('Map<String, int>'));
expect(TypeConversionUtils.pythonToDartType('dict'),
equals('Map<String, dynamic>'));
});
test('converts Optional types correctly', () {
expect(TypeConversionUtils.pythonToDartType('Optional[str]'),
equals('String?'));
expect(TypeConversionUtils.pythonToDartType('Optional[int]'),
equals('int?'));
expect(TypeConversionUtils.pythonToDartType('Optional[dict]'),
equals('Map<String, dynamic>?'));
expect(TypeConversionUtils.pythonToDartType('Optional[List[str]]'),
equals('List<String>?'));
});
test('handles nested generic types', () {
expect(TypeConversionUtils.pythonToDartType('List[Optional[str]]'),
equals('List<String?>'));
expect(TypeConversionUtils.pythonToDartType('Dict[str, List[int]]'),
equals('Map<String, List<int>>'));
expect(
TypeConversionUtils.pythonToDartType(
'Optional[Dict[str, List[int]]]'),
equals('Map<String, List<int>>?'));
});
});
group('getDefaultValue', () {
test('returns correct default values for basic types', () {
expect(TypeConversionUtils.getDefaultValue('bool'), equals('false'));
expect(TypeConversionUtils.getDefaultValue('int'), equals('0'));
expect(TypeConversionUtils.getDefaultValue('double'), equals('0.0'));
expect(TypeConversionUtils.getDefaultValue('String'), equals("''"));
});
test('returns correct default values for nullable types', () {
expect(TypeConversionUtils.getDefaultValue('bool?'), equals('false'));
expect(TypeConversionUtils.getDefaultValue('int?'), equals('0'));
expect(TypeConversionUtils.getDefaultValue('double?'), equals('0.0'));
expect(TypeConversionUtils.getDefaultValue('String?'), equals("''"));
});
test('returns correct default values for collection types', () {
expect(TypeConversionUtils.getDefaultValue('List'), equals('[]'));
expect(
TypeConversionUtils.getDefaultValue('List<String>'), equals('[]'));
expect(TypeConversionUtils.getDefaultValue('Map<String, dynamic>'),
equals('{}'));
expect(TypeConversionUtils.getDefaultValue('Map<String, int>'),
equals('{}'));
});
test('returns null for unknown types', () {
expect(
TypeConversionUtils.getDefaultValue('CustomType'), equals('null'));
expect(TypeConversionUtils.getDefaultValue('UnknownType?'),
equals('null'));
});
});
});
}

View file

@ -0,0 +1,45 @@
import 'package:test/test.dart';
import '../../lib/src/utils/type_utils.dart';
void main() {
group('TypeUtils', () {
test('castToMapList handles null input', () {
expect(TypeUtils.castToMapList(null), isEmpty);
});
test('castToMapList converts List<dynamic> to List<Map<String, dynamic>>',
() {
final input = [
{'name': 'test', 'value': 1},
{'type': 'string', 'optional': true}
];
final result = TypeUtils.castToMapList(input);
expect(result, isA<List<Map<String, dynamic>>>());
expect(result.first['name'], equals('test'));
expect(result.last['type'], equals('string'));
});
test('castToMap handles null input', () {
expect(TypeUtils.castToMap(null), isEmpty);
});
test('castToMap converts dynamic to Map<String, dynamic>', () {
final input = {'name': 'test', 'value': 1};
final result = TypeUtils.castToMap(input);
expect(result, isA<Map<String, dynamic>>());
expect(result['name'], equals('test'));
expect(result['value'], equals(1));
});
test('castToStringList handles null input', () {
expect(TypeUtils.castToStringList(null), isEmpty);
});
test('castToStringList converts List<dynamic> to List<String>', () {
final input = ['test', 1, true];
final result = TypeUtils.castToStringList(input);
expect(result, isA<List<String>>());
expect(result, equals(['test', '1', 'true']));
});
});
}

View file

@ -0,0 +1,90 @@
import 'package:test/test.dart';
import 'package:yaml/yaml.dart';
import '../lib/src/utils/yaml_utils.dart';
void main() {
group('YamlUtils', () {
test('converts simple YAML to Map correctly', () {
final yamlStr = '''
interfaces:
- name: TestInterface
methods:
- name: testMethod
arguments:
- name: arg1
type: str
return_type: str
''';
final yaml = loadYaml(yamlStr) as YamlMap;
final map = YamlUtils.convertYamlToMap(yaml);
expect(map, isA<Map<String, dynamic>>());
expect(map['interfaces'], isA<List>());
expect(map['interfaces'][0]['name'], equals('TestInterface'));
expect(map['interfaces'][0]['methods'][0]['arguments'][0]['type'],
equals('str'));
});
test('handles nested YAML structures', () {
final yamlStr = '''
interfaces:
- name: TestInterface
properties:
- name: prop1
type: List[str]
has_default: true
methods:
- name: testMethod
arguments:
- name: arg1
type: Dict[str, Any]
is_optional: true
return_type: Optional[int]
''';
final yaml = loadYaml(yamlStr) as YamlMap;
final map = YamlUtils.convertYamlToMap(yaml);
expect(
map['interfaces'][0]['properties'][0]['type'], equals('List[str]'));
expect(map['interfaces'][0]['methods'][0]['arguments'][0]['type'],
equals('Dict[str, Any]'));
});
test('converts actual contract YAML correctly', () {
final yamlStr = '''
interfaces:
- name: LLMProtocol
bases:
- Protocol
methods:
- name: generate
arguments:
- name: prompts
type: List[str]
is_optional: false
has_default: false
return_type: List[str]
docstring: Generate completions for the prompts.
decorators:
- name: abstractmethod
is_abstract: true
properties: []
docstring: Protocol for language models.
is_interface: true
''';
final yaml = loadYaml(yamlStr) as YamlMap;
final map = YamlUtils.convertYamlToMap(yaml);
expect(map['interfaces'][0]['name'], equals('LLMProtocol'));
expect(map['interfaces'][0]['bases'][0], equals('Protocol'));
expect(map['interfaces'][0]['methods'][0]['name'], equals('generate'));
expect(map['interfaces'][0]['methods'][0]['arguments'][0]['type'],
equals('List[str]'));
expect(map['interfaces'][0]['docstring'],
equals('Protocol for language models.'));
});
});
}

View file

@ -0,0 +1,57 @@
import 'package:test/test.dart';
import 'package:yaml/yaml.dart';
import '../lib/src/utils/yaml_utils.dart';
import '../lib/src/utils/type_utils.dart';
void main() {
group('YAML Type Casting', () {
test('converts YAML data to properly typed maps and lists', () {
final yamlStr = '''
classes:
- name: TestClass
properties:
- name: model_name
type: String
has_default: false
- name: is_ready
type: bool
has_default: true
methods:
- name: process
return_type: String
arguments:
- name: input
type: String
is_optional: false
''';
final yamlDoc = loadYaml(yamlStr) as YamlMap;
final data = YamlUtils.convertYamlToMap(yamlDoc);
final classes = data['classes'] as List;
final firstClass = classes.first as Map<String, dynamic>;
// Test properties casting
final properties =
TypeUtils.castToMapList(firstClass['properties'] as List?);
expect(properties, isA<List<Map<String, dynamic>>>());
expect(properties.first['name'], equals('model_name'));
expect(properties.first['type'], equals('String'));
expect(properties.first['has_default'], isFalse);
// Test methods casting
final methods = TypeUtils.castToMapList(firstClass['methods'] as List?);
expect(methods, isA<List<Map<String, dynamic>>>());
expect(methods.first['name'], equals('process'));
expect(methods.first['return_type'], equals('String'));
// Test nested arguments casting
final arguments =
TypeUtils.castToMapList(methods.first['arguments'] as List?);
expect(arguments, isA<List<Map<String, dynamic>>>());
expect(arguments.first['name'], equals('input'));
expect(arguments.first['type'], equals('String'));
expect(arguments.first['is_optional'], isFalse);
});
});
}

View file

@ -0,0 +1,255 @@
import 'dart:io';
import 'package:args/args.dart';
import 'python_parser.dart';
/// Represents a Python class or interface contract
class ContractDefinition {
final String name;
final List<String> bases;
final List<MethodDefinition> methods;
final List<PropertyDefinition> properties;
final String? docstring;
final List<Map<String, dynamic>> decorators;
final bool isInterface;
ContractDefinition({
required this.name,
required this.bases,
required this.methods,
required this.properties,
this.docstring,
required this.decorators,
required this.isInterface,
});
Map<String, dynamic> toJson() => {
'name': name,
'bases': bases,
'methods': methods.map((m) => m.toJson()).toList(),
'properties': properties.map((p) => p.toJson()).toList(),
if (docstring != null) 'docstring': docstring,
'decorators': decorators,
'is_interface': isInterface,
};
/// Create ContractDefinition from PythonClass
factory ContractDefinition.fromPythonClass(PythonClass pythonClass) {
return ContractDefinition(
name: pythonClass.name,
bases: pythonClass.bases,
methods: pythonClass.methods
.map((m) => MethodDefinition(
name: m.name,
arguments: m.parameters
.map((p) => ArgumentDefinition(
name: p.name,
type: p.type,
isOptional: p.isOptional,
hasDefault: p.hasDefault,
))
.toList(),
returnType: m.returnType,
docstring: m.docstring,
decorators: m.decorators.map((d) => {'name': d}).toList(),
isAbstract: m.isAbstract,
))
.toList(),
properties: pythonClass.properties
.map((p) => PropertyDefinition(
name: p.name,
type: p.type,
hasDefault: p.hasDefault,
))
.toList(),
docstring: pythonClass.docstring,
decorators: pythonClass.decorators.map((d) => {'name': d}).toList(),
isInterface: pythonClass.isInterface,
);
}
}
/// Represents a method in a contract
class MethodDefinition {
final String name;
final List<ArgumentDefinition> arguments;
final String returnType;
final String? docstring;
final List<Map<String, dynamic>> decorators;
final bool isAbstract;
MethodDefinition({
required this.name,
required this.arguments,
required this.returnType,
this.docstring,
required this.decorators,
required this.isAbstract,
});
Map<String, dynamic> toJson() => {
'name': name,
'arguments': arguments.map((a) => a.toJson()).toList(),
'return_type': returnType,
if (docstring != null) 'docstring': docstring,
'decorators': decorators,
'is_abstract': isAbstract,
};
}
/// Represents a method argument
class ArgumentDefinition {
final String name;
final String type;
final bool isOptional;
final bool hasDefault;
ArgumentDefinition({
required this.name,
required this.type,
required this.isOptional,
required this.hasDefault,
});
Map<String, dynamic> toJson() => {
'name': name,
'type': type,
'is_optional': isOptional,
'has_default': hasDefault,
};
}
/// Represents a class property
class PropertyDefinition {
final String name;
final String type;
final bool hasDefault;
PropertyDefinition({
required this.name,
required this.type,
required this.hasDefault,
});
Map<String, dynamic> toJson() => {
'name': name,
'type': type,
'has_default': hasDefault,
};
}
/// Main contract extractor class
class ContractExtractor {
final List<ContractDefinition> interfaces = [];
final List<ContractDefinition> classes = [];
/// Process a Python source file and extract contracts
Future<void> processFile(File file) async {
try {
final pythonClasses = await PythonParser.parseFile(file);
for (final pythonClass in pythonClasses) {
final contract = ContractDefinition.fromPythonClass(pythonClass);
if (pythonClass.isInterface) {
interfaces.add(contract);
} else {
classes.add(contract);
}
}
} catch (e) {
print('Error processing file ${file.path}: $e');
}
}
/// Process all Python files in a directory recursively
Future<void> processDirectory(String dirPath) async {
final dir = Directory(dirPath);
await for (final entity in dir.list(recursive: true)) {
if (entity is File && entity.path.endsWith('.py')) {
await processFile(entity);
}
}
}
/// Generate YAML output
Future<void> generateYaml(String outputPath) async {
final output = {
'interfaces': interfaces.map((i) => i.toJson()).toList(),
'classes': classes.map((c) => c.toJson()).toList(),
};
final yamlString = mapToYaml(output);
final file = File(outputPath);
await file.writeAsString(yamlString);
}
}
/// Converts a Map to YAML string with proper formatting
String mapToYaml(Map<String, dynamic> map, {int indent = 0}) {
final buffer = StringBuffer();
final indentStr = ' ' * indent;
map.forEach((key, value) {
if (value is Map) {
buffer.writeln('$indentStr$key:');
buffer
.write(mapToYaml(value as Map<String, dynamic>, indent: indent + 2));
} else if (value is List) {
buffer.writeln('$indentStr$key:');
for (var item in value) {
if (item is Map) {
buffer.writeln('$indentStr- ');
buffer.write(
mapToYaml(item as Map<String, dynamic>, indent: indent + 4));
} else {
buffer.writeln('$indentStr- $item');
}
}
} else {
if (value == null) {
buffer.writeln('$indentStr$key: null');
} else if (value is String) {
// Handle multi-line strings
if (value.contains('\n')) {
buffer.writeln('$indentStr$key: |');
value.split('\n').forEach((line) {
buffer.writeln('$indentStr $line');
});
} else {
buffer.writeln('$indentStr$key: "$value"');
}
} else {
buffer.writeln('$indentStr$key: $value');
}
}
});
return buffer.toString();
}
void main(List<String> arguments) async {
final parser = ArgParser()
..addOption('source',
abbr: 's',
help: 'Source directory containing Python LangChain implementation',
mandatory: true)
..addOption('output',
abbr: 'o', help: 'Output YAML file path', mandatory: true);
try {
final results = parser.parse(arguments);
final sourceDir = results['source'] as String;
final outputFile = results['output'] as String;
final extractor = ContractExtractor();
await extractor.processDirectory(sourceDir);
await extractor.generateYaml(outputFile);
print('Contract extraction completed successfully.');
print('Interfaces found: ${extractor.interfaces.length}');
print('Classes found: ${extractor.classes.length}');
} catch (e) {
print('Error: $e');
print('Usage: dart extract_contracts.dart --source <dir> --output <file>');
exit(1);
}
}

View file

@ -0,0 +1,209 @@
import 'dart:io';
import 'package:yaml/yaml.dart';
import 'package:path/path.dart' as path;
import 'package:args/args.dart';
import 'package:converter/src/utils/yaml_utils.dart';
import 'package:converter/src/utils/name_utils.dart';
import 'package:converter/src/utils/class_generator_utils.dart';
import 'package:converter/src/utils/type_utils.dart';
import 'package:converter/src/utils/type_conversion_utils.dart';
/// Generates a Dart interface from a contract
String generateInterface(Map<String, dynamic> interface) {
final buffer = StringBuffer();
final name = interface['name'] as String;
final docstring = interface['docstring'] as String?;
// Add documentation
if (docstring != null) {
buffer.writeln('/// ${docstring.replaceAll('\n', '\n/// ')}');
}
// Begin interface definition
buffer.writeln('abstract class $name {');
// Generate properties
final properties = interface['properties'] as List?;
if (properties != null) {
for (final prop in properties) {
final propName = NameUtils.toDartName(prop['name'] as String);
final propType =
TypeConversionUtils.pythonToDartType(prop['type'] as String);
buffer.writeln(' $propType get $propName;');
// Only generate setter if is_readonly is explicitly false
final isReadonly = prop['is_readonly'];
if (isReadonly != null && !isReadonly) {
buffer.writeln(' set $propName($propType value);');
}
}
if (properties.isNotEmpty) buffer.writeln();
}
// Generate methods
final methods = interface['methods'] as List?;
if (methods != null) {
for (final method in methods) {
final methodName = NameUtils.toDartName(method['name'] as String);
final returnType =
TypeConversionUtils.pythonToDartType(method['return_type'] as String);
final methodDoc = method['docstring'] as String?;
final decorators = TypeUtils.castToMapList(method['decorators'] as List?);
final isProperty = decorators.any((d) => d['name'] == 'property');
if (methodDoc != null) {
buffer.writeln(' /// ${methodDoc.replaceAll('\n', '\n /// ')}');
}
if (isProperty) {
// Generate as a getter
buffer.writeln(' $returnType get $methodName;');
} else {
// Generate as a method
final isAsync = method['is_async'] == true;
if (isAsync) {
buffer.write(' Future<$returnType> $methodName(');
} else {
buffer.write(' $returnType $methodName(');
}
// Generate parameters
final params = method['arguments'] as List?;
if (params != null && params.isNotEmpty) {
final paramStrings = <String>[];
for (final param in params) {
final paramName = NameUtils.toDartName(param['name'] as String);
final paramType =
TypeConversionUtils.pythonToDartType(param['type'] as String);
final isOptional = param['is_optional'] == true;
if (isOptional) {
paramStrings.add('[$paramType $paramName]');
} else {
paramStrings.add('$paramType $paramName');
}
}
buffer.write(paramStrings.join(', '));
}
buffer.writeln(');');
}
}
}
buffer.writeln('}');
return buffer.toString();
}
/// Generates a Dart class implementation from a contract
String generateClass(Map<String, dynamic> classContract) {
final buffer = StringBuffer();
final name = classContract['name'] as String;
final bases = TypeUtils.castToStringList(classContract['bases'] as List?);
final docstring = classContract['docstring'] as String?;
// Add documentation
if (docstring != null) {
buffer.writeln('/// ${docstring.replaceAll('\n', '\n/// ')}');
}
// Begin class definition
buffer.write('class $name');
if (bases.isNotEmpty) {
final implementsStr = bases.join(', ');
buffer.write(' implements $implementsStr');
}
buffer.writeln(' {');
// Generate required interface implementations first
if (bases.contains('BaseChain')) {
buffer.write(ClassGeneratorUtils.generateRequiredImplementations(
bases, classContract));
}
// Generate properties from contract properties
final properties =
TypeUtils.castToMapList(classContract['properties'] as List?);
if (properties.isNotEmpty) {
buffer.write(ClassGeneratorUtils.generateProperties(properties));
}
// Generate constructor
if (properties.isNotEmpty || bases.contains('BaseChain')) {
buffer.write(ClassGeneratorUtils.generateConstructor(name, properties));
}
// Generate additional methods
final methods = TypeUtils.castToMapList(classContract['methods'] as List?);
if (methods.isNotEmpty) {
for (final method in methods) {
if (method['name'] != '__init__') {
buffer.write(ClassGeneratorUtils.generateMethod(method));
}
}
}
buffer.writeln('}');
return buffer.toString();
}
/// Main code generator class
class DartCodeGenerator {
final String outputDir;
DartCodeGenerator(this.outputDir);
Future<void> generateFromYaml(String yamlPath) async {
final file = File(yamlPath);
final content = await file.readAsString();
final yamlDoc = loadYaml(content) as YamlMap;
final contracts = YamlUtils.convertYamlToMap(yamlDoc);
// Generate interfaces
for (final interface in contracts['interfaces'] ?? []) {
final code = generateInterface(interface as Map<String, dynamic>);
final fileName = '${interface['name'].toString().toLowerCase()}.dart';
final outputFile =
File(path.join(outputDir, 'lib', 'src', 'interfaces', fileName));
await outputFile.create(recursive: true);
await outputFile.writeAsString(code);
}
// Generate classes
for (final classContract in contracts['classes'] ?? []) {
final code = generateClass(classContract as Map<String, dynamic>);
final fileName = '${classContract['name'].toString().toLowerCase()}.dart';
final outputFile =
File(path.join(outputDir, 'lib', 'src', 'implementations', fileName));
await outputFile.create(recursive: true);
await outputFile.writeAsString(code);
}
}
}
void main(List<String> arguments) async {
final parser = ArgParser()
..addOption('contracts',
abbr: 'c', help: 'Path to the YAML contracts file', mandatory: true)
..addOption('output',
abbr: 'o',
help: 'Output directory for generated Dart code',
mandatory: true);
try {
final results = parser.parse(arguments);
final contractsFile = results['contracts'] as String;
final outputDir = results['output'] as String;
final generator = DartCodeGenerator(outputDir);
await generator.generateFromYaml(contractsFile);
print('Code generation completed successfully.');
} catch (e) {
print('Error: $e');
print(
'Usage: dart generate_dart_code.dart --contracts <file> --output <dir>');
exit(1);
}
}

View file

@ -0,0 +1,443 @@
import 'dart:io';
/// Represents a Python method parameter
class Parameter {
final String name;
final String type;
final bool isOptional;
final bool hasDefault;
Parameter({
required this.name,
required this.type,
required this.isOptional,
required this.hasDefault,
});
Map<String, dynamic> toJson() => {
'name': name,
'type': type,
'is_optional': isOptional,
'has_default': hasDefault,
};
}
/// Represents a Python method
class Method {
final String name;
final List<Parameter> parameters;
final String returnType;
final String? docstring;
final List<String> decorators;
final bool isAsync;
final bool isAbstract;
final bool isProperty;
Method({
required this.name,
required this.parameters,
required this.returnType,
this.docstring,
required this.decorators,
required this.isAsync,
required this.isAbstract,
required this.isProperty,
});
Map<String, dynamic> toJson() => {
'name': name,
'parameters': parameters.map((p) => p.toJson()).toList(),
'return_type': returnType,
if (docstring != null) 'docstring': docstring,
'decorators': decorators,
'is_async': isAsync,
'is_abstract': isAbstract,
'is_property': isProperty,
};
}
/// Represents a Python class property
class Property {
final String name;
final String type;
final bool hasDefault;
final String? defaultValue;
Property({
required this.name,
required this.type,
required this.hasDefault,
this.defaultValue,
});
Map<String, dynamic> toJson() => {
'name': name,
'type': type,
'has_default': hasDefault,
if (defaultValue != null) 'default_value': defaultValue,
};
}
/// Represents a Python class
class PythonClass {
final String name;
final List<String> bases;
final List<Method> methods;
final List<Property> properties;
final String? docstring;
final List<String> decorators;
final bool isInterface;
PythonClass({
required this.name,
required this.bases,
required this.methods,
required this.properties,
this.docstring,
required this.decorators,
required this.isInterface,
});
Map<String, dynamic> toJson() => {
'name': name,
'bases': bases,
'methods': methods.map((m) => m.toJson()).toList(),
'properties': properties.map((p) => p.toJson()).toList(),
if (docstring != null) 'docstring': docstring,
'decorators': decorators,
'is_interface': isInterface,
};
}
/// Parser for Python source code
class PythonParser {
/// Check if a line looks like code
static bool _isCodeLine(String line) {
return line.startsWith('def ') ||
line.startsWith('@') ||
line.startsWith('class ') ||
line.contains(' = ') ||
line.contains('self.') ||
line.contains('return ') ||
line.contains('pass') ||
line.contains('raise ') ||
line.contains('yield ') ||
line.contains('async ') ||
line.contains('await ') ||
(line.contains(':') && !line.startsWith('Note:')) ||
line.trim().startsWith('"""') ||
line.trim().endsWith('"""');
}
/// Parse a docstring from Python code lines
static String? _parseDocstring(
List<String> lines, int startIndex, int baseIndent) {
if (startIndex >= lines.length) return null;
final line = lines[startIndex].trim();
if (!line.startsWith('"""')) return null;
// Handle single-line docstring
if (line.endsWith('"""') && line.length > 6) {
return line.substring(3, line.length - 3).trim();
}
final docLines = <String>[];
// Add first line content if it exists after the opening quotes
var firstLineContent = line.substring(3).trim();
if (firstLineContent.isNotEmpty && !_isCodeLine(firstLineContent)) {
docLines.add(firstLineContent);
}
var i = startIndex + 1;
while (i < lines.length) {
final currentLine = lines[i].trim();
// Stop at closing quotes
if (currentLine.endsWith('"""')) {
// Add the last line content if it exists before the closing quotes
var lastLineContent =
currentLine.substring(0, currentLine.length - 3).trim();
if (lastLineContent.isNotEmpty && !_isCodeLine(lastLineContent)) {
docLines.add(lastLineContent);
}
break;
}
// Only add non-code lines
if (currentLine.isNotEmpty && !_isCodeLine(currentLine)) {
docLines.add(currentLine);
}
i++;
}
return docLines.isEmpty ? null : docLines.join('\n').trim();
}
/// Get the indentation level of a line
static int _getIndentation(String line) {
return line.length - line.trimLeft().length;
}
/// Parse method parameters from a parameter string
static List<Parameter> _parseParameters(String paramsStr) {
if (paramsStr.trim().isEmpty) return [];
final params = <Parameter>[];
var depth = 0;
var currentParam = StringBuffer();
// Handle nested brackets in parameter types
for (var i = 0; i < paramsStr.length; i++) {
final char = paramsStr[i];
if (char == '[') depth++;
if (char == ']') depth--;
if (char == ',' && depth == 0) {
final param = currentParam.toString().trim();
if (param.isNotEmpty && param != 'self' && !param.startsWith('**')) {
final paramObj = _parseParameter(param);
if (paramObj != null) {
params.add(paramObj);
}
}
currentParam.clear();
} else {
currentParam.write(char);
}
}
final lastParam = currentParam.toString().trim();
if (lastParam.isNotEmpty &&
lastParam != 'self' &&
!lastParam.startsWith('**')) {
final paramObj = _parseParameter(lastParam);
if (paramObj != null) {
params.add(paramObj);
}
}
return params;
}
/// Parse a single parameter
static Parameter? _parseParameter(String param) {
if (param.isEmpty) return null;
var name = param;
var type = 'Any';
var hasDefault = false;
var isOptional = false;
// Check for type annotation
if (param.contains(':')) {
final parts = param.split(':');
name = parts[0].trim();
var typeStr = parts[1];
// Handle default value
if (typeStr.contains('=')) {
final typeParts = typeStr.split('=');
typeStr = typeParts[0];
hasDefault = true;
isOptional = true;
}
type = typeStr.trim();
// Handle Optional type
if (type.startsWith('Optional[')) {
type = type.substring(9, type.length - 1);
isOptional = true;
}
}
// Check for default value without type annotation
if (param.contains('=')) {
hasDefault = true;
isOptional = true;
if (!param.contains(':')) {
name = param.split('=')[0].trim();
}
}
return Parameter(
name: name,
type: type,
isOptional: isOptional,
hasDefault: hasDefault,
);
}
/// Parse a method definition
static Method? _parseMethod(
List<String> lines, int startIndex, List<String> decorators) {
final line = lines[startIndex].trim();
if (!line.startsWith('def ') && !line.startsWith('async def ')) return null;
final methodMatch =
RegExp(r'(?:async\s+)?def\s+(\w+)\s*\((.*?)\)(?:\s*->\s*(.+?))?\s*:')
.firstMatch(line);
if (methodMatch == null) return null;
final name = methodMatch.group(1)!;
final paramsStr = methodMatch.group(2) ?? '';
var returnType = methodMatch.group(3) ?? 'None';
returnType = returnType.trim();
final isAsync = line.contains('async ');
final isAbstract = decorators.contains('abstractmethod');
final isProperty = decorators.contains('property');
// Parse docstring if present
var i = startIndex + 1;
String? docstring;
if (i < lines.length) {
final nextLine = lines[i].trim();
if (nextLine.startsWith('"""')) {
docstring =
_parseDocstring(lines, i, _getIndentation(lines[startIndex]));
}
}
return Method(
name: name,
parameters: _parseParameters(paramsStr),
returnType: returnType,
docstring: docstring,
decorators: decorators,
isAsync: isAsync,
isAbstract: isAbstract,
isProperty: isProperty,
);
}
/// Parse a property definition
static Property? _parseProperty(String line) {
if (!line.contains(':') || line.contains('def ')) return null;
final propertyMatch =
RegExp(r'(\w+)\s*:\s*(.+?)(?:\s*=\s*(.+))?$').firstMatch(line);
if (propertyMatch == null) return null;
final name = propertyMatch.group(1)!;
final type = propertyMatch.group(2)!;
final defaultValue = propertyMatch.group(3);
return Property(
name: name,
type: type.trim(),
hasDefault: defaultValue != null,
defaultValue: defaultValue?.trim(),
);
}
/// Parse Python source code into a list of classes
static Future<List<PythonClass>> parseFile(File file) async {
final content = await file.readAsString();
final lines = content.split('\n');
final classes = <PythonClass>[];
for (var i = 0; i < lines.length; i++) {
final line = lines[i];
final trimmedLine = line.trim();
if (trimmedLine.startsWith('class ')) {
final classMatch =
RegExp(r'class\s+(\w+)(?:\((.*?)\))?:').firstMatch(trimmedLine);
if (classMatch != null) {
final className = classMatch.group(1)!;
final basesStr = classMatch.group(2);
final bases =
basesStr?.split(',').map((b) => b.trim()).toList() ?? [];
final isInterface = bases.any((b) => b.contains('Protocol'));
final classIndent = _getIndentation(line);
var currentDecorators = <String>[];
final methods = <Method>[];
final properties = <Property>[];
// Parse class docstring
var j = i + 1;
String? docstring;
if (j < lines.length && lines[j].trim().startsWith('"""')) {
docstring = _parseDocstring(lines, j, classIndent);
// Skip past docstring
while (j < lines.length && !lines[j].trim().endsWith('"""')) {
j++;
}
j++;
}
// Parse class body
while (j < lines.length) {
final currentLine = lines[j];
final currentIndent = _getIndentation(currentLine);
final trimmedCurrentLine = currentLine.trim();
// Check if we're still in the class
if (trimmedCurrentLine.isNotEmpty && currentIndent <= classIndent) {
break;
}
// Skip empty lines
if (trimmedCurrentLine.isEmpty) {
j++;
continue;
}
// Parse decorators
if (trimmedCurrentLine.startsWith('@')) {
currentDecorators
.add(trimmedCurrentLine.substring(1).split('(')[0].trim());
j++;
continue;
}
// Parse methods
if (trimmedCurrentLine.startsWith('def ') ||
trimmedCurrentLine.startsWith('async def ')) {
final method =
_parseMethod(lines, j, List.from(currentDecorators));
if (method != null) {
methods.add(method);
currentDecorators = [];
// Skip past method body
while (j < lines.length - 1) {
final nextLine = lines[j + 1];
if (nextLine.trim().isEmpty ||
_getIndentation(nextLine) <= currentIndent) {
break;
}
j++;
}
}
}
// Parse properties
final property = _parseProperty(trimmedCurrentLine);
if (property != null) {
properties.add(property);
}
j++;
}
i = j - 1;
classes.add(PythonClass(
name: className,
bases: bases,
methods: methods,
properties: properties,
docstring: docstring,
decorators: [],
isInterface: isInterface,
));
}
}
}
return classes;
}
}

View file

@ -0,0 +1,152 @@
#!/bin/bash
# Exit on error
set -e
# Script directory
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
PACKAGE_DIR="$(dirname "$SCRIPT_DIR")"
TEMP_DIR="$PACKAGE_DIR/temp"
CONTRACTS_FILE="$TEMP_DIR/contracts.yaml"
# Colors for output
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Print step information
print_step() {
echo -e "${BLUE}=== $1 ===${NC}"
}
# Ensure required commands are available
check_requirements() {
print_step "Checking requirements"
commands=("git" "dart" "pub")
for cmd in "${commands[@]}"; do
if ! command -v $cmd &> /dev/null; then
echo "Error: $cmd is required but not installed."
exit 1
fi
done
}
# Create necessary directories
setup_directories() {
print_step "Setting up directories"
mkdir -p "$TEMP_DIR"
mkdir -p "$PACKAGE_DIR/lib/src/interfaces"
mkdir -p "$PACKAGE_DIR/lib/src/implementations"
}
# Clone Python LangChain repository
clone_langchain() {
print_step "Cloning Python LangChain repository"
if [ -d "$TEMP_DIR/langchain" ]; then
echo "Updating existing LangChain repository..."
cd "$TEMP_DIR/langchain"
git pull
else
echo "Cloning LangChain repository..."
git clone https://github.com/langchain-ai/langchain.git "$TEMP_DIR/langchain"
fi
}
# Extract contracts from Python code
extract_contracts() {
print_step "Extracting contracts from Python code"
cd "$PACKAGE_DIR"
dart run "$SCRIPT_DIR/extract_contracts.dart" \
--source "$TEMP_DIR/langchain/langchain" \
--output "$CONTRACTS_FILE"
}
# Generate Dart code from contracts
generate_dart_code() {
print_step "Generating Dart code from contracts"
cd "$PACKAGE_DIR"
dart run "$SCRIPT_DIR/generate_dart_code.dart" \
--contracts "$CONTRACTS_FILE" \
--output "$PACKAGE_DIR"
}
# Update package dependencies
update_dependencies() {
print_step "Updating package dependencies"
cd "$PACKAGE_DIR"
# Ensure required dependencies are in pubspec.yaml
if ! grep -q "yaml:" pubspec.yaml; then
echo "
dependencies:
yaml: ^3.1.0
path: ^1.8.0
args: ^2.3.0" >> pubspec.yaml
fi
dart pub get
}
# Create package exports file
create_exports() {
print_step "Creating package exports"
cat > "$PACKAGE_DIR/lib/langchain.dart" << EOL
/// LangChain for Dart
///
/// This is a Dart implementation of LangChain, providing tools and utilities
/// for building applications powered by large language models (LLMs).
library langchain;
// Export interfaces
export 'src/interfaces/llm.dart';
export 'src/interfaces/chain.dart';
export 'src/interfaces/prompt.dart';
export 'src/interfaces/memory.dart';
export 'src/interfaces/embeddings.dart';
export 'src/interfaces/document.dart';
export 'src/interfaces/vectorstore.dart';
export 'src/interfaces/tool.dart';
export 'src/interfaces/agent.dart';
// Export implementations
export 'src/implementations/llm.dart';
export 'src/implementations/chain.dart';
export 'src/implementations/prompt.dart';
export 'src/implementations/memory.dart';
export 'src/implementations/embeddings.dart';
export 'src/implementations/document.dart';
export 'src/implementations/vectorstore.dart';
export 'src/implementations/tool.dart';
export 'src/implementations/agent.dart';
EOL
}
# Main execution
main() {
print_step "Starting LangChain setup"
check_requirements
setup_directories
clone_langchain
extract_contracts
generate_dart_code
update_dependencies
create_exports
echo -e "${GREEN}Setup completed successfully!${NC}"
echo "Next steps:"
echo "1. Review generated code in lib/src/"
echo "2. Implement TODOs in the generated classes"
echo "3. Add tests for the implementations"
echo "4. Update the documentation"
}
# Run main function
main

View file

@ -0,0 +1,53 @@
#!/bin/bash
# Array of extensions to uninstall
extensions=(
"nash.awesome-flutter-snippets" # Dart Data Class Generator
"robert-brunhage.flutter-riverpod-snippets" # Flutter Riverpod Snippets
"usernamehw.errorlens" # Error Lens
"aaron-bond.better-comments" # Better Comments
"styfle.remove-comments" # Remove Comments
"patbenatar.advanced-new-file" # Advanced New File
"GitHub.copilot" # GitHub Copilot
"dracula-theme.theme-dracula" # Dracula Theme (optional)
"firebase.vscode-firebase-explorer" # Firebase Explorer
"pflannery.vscode-versionlens" # Version Lens
"tgsup.find-unused-dart-files-and-assets" # Find Unused Dart Files & Assets
"humao.rest-client" # REST Client
"rangav.vscode-thunder-client" # Thunder Client
"ritwickdey.liveserver" # Live Server
"Dart-Code.dart-code" # Dart SDK
"Dart-Code.flutter" # Flutter SDK
"ms-vscode.cpptools" # C/C++
"ms-vscode.cpptools-extension-pack" # C/C++ Extension Pack
"ms-vscode.cpptools-themes" # C/C++ Themes
"twxs.cmake " # CMake
"ms-vscode.cmake-tools" # CMake Tools
"ms-vscode.makefile-tools" # Makefile Tools
"saoudrizwan.claude-dev" # Claude Dev
"Continue.continue" # Continue
"DEVSENSE.phptools-vscode" # PHP Tools
"DEVSENSE.composer-php-vscode" # Composer PHP
"DEVSENSE.profiler-php-vscode" # Profiler PHP
"ms-vscode.remote-explorer" # Remote - Containers
"ms-vscode-remote.remote-ssh" # Remote - SSH
"ms-vscode-remote.remote-ssh-edit" # Remote - SSH: Edit
"ms-vscode-remote.remote-containers" # Remote - Containers
"eamodio.gitlens" # GitLens
"DEVSENSE.intelli-php-vscode" # IntelliPHP
"blaugold.melos-code" # Melos
"vscode-icons-team.vscode-icons" # VSCode Icons
"redhat.vscode-yaml" # YAML
"GitHub.vscode-github-actions" # GitHub Actions
"ms-azuretools.vscode-docker" # Docker
"ms-kubernetes-tools.vscode-kubernetes-tools" # Kubernetes
)
# Uninstall each extension
echo "Uninstalling VSCode extensions..."
for extension in "${extensions[@]}"; do
code --uninstall-extension "$extension"
echo "Uninstalled: $extension"
done
echo "All specified extensions have been uninstalled successfully."

View file

@ -11,7 +11,9 @@
name: protevus_platform name: protevus_platform
repository: https://github.com/protevus/platform repository: https://github.com/protevus/platform
packages: packages:
- apps/**
- packages/** - packages/**
- helpers/tools/**
- examples/** - examples/**
command: command:
@ -74,12 +76,20 @@ scripts:
configure: configure:
run: "melos bootstrap && MELOS_SCOPE=\"platform_container_generator\" melos run generate:custom && MELOS_SCOPE=\"platform_model, platform_exceptions, platform_mocking\" melos run generate:dummy:test && MELOS_SCOPE=\"platform_container_generator\" melos run debug:reflectable && melos run test && melos run coverage && melos run coverage_report && melos run docs:generate\n" run: "melos bootstrap && MELOS_SCOPE=\"platform_container_generator\" melos run generate:custom && MELOS_SCOPE=\"platform_model, platform_exceptions, platform_mocking\" melos run generate:dummy:test && MELOS_SCOPE=\"platform_container_generator\" melos run debug:reflectable && melos run test && melos run coverage && melos run coverage_report && melos run docs:generate\n"
description: "Configure the development environment, generate code and dummy tests, run tests, generate coverage, and create API documentation" description: "Configure the development environment, generate code and dummy tests, run tests, generate coverage, and create API documentation"
template:
name: Create from template
description: "Creates a new project from a template in the templates directory.\n\nUsage: melos run template template_name:name type:dart|flutter name:project_name\n\nExample:\n melos run template template_name:bloc_app type:flutter name:my_new_app\n melos run template template_name:core_package type:dart name:core_utils\n"
run: dart run helpers/create_from_template.dart $MELOS_ARGS
test: test:
run: melos exec -c 1 --fail-fast -- "dart test" run: melos exec -c 1 --fail-fast -- "dart test"
description: Run tests for all packages description: Run tests for all packages
test:custom: test:custom:
run: melos exec --scope="$MELOS_SCOPE" -- dart test run: melos exec --scope="$MELOS_SCOPE" -- dart test
description: Run tests for specified packages (use with MELOS_SCOPE env var) description: Run tests for specified packages (use with MELOS_SCOPE env var)
create:
name: Create new package or application
description: "Creates a new Dart package or Flutter application in the appropriate directory.\n\nUsage: melos run create -- --type dart|flutter --category type --name project_name\n\nAvailable categories for Dart:\n - package : Basic Dart package\n - console : Command-line application\n - server : Server-side application\n - desktop : Desktop application\n - plugin : Dart plugin\n\nAvailable categories for Flutter:\n - app : Mobile application\n - web : Web application\n - desktop : Desktop application\n - plugin : Flutter plugin\n - module : Flutter module\n - package : Flutter package\n"
run: dart run helpers/create_project.dart $MELOS_ARGS
deps:check: deps:check:
run: melos exec -- "dart pub outdated" run: melos exec -- "dart pub outdated"
description: Check for outdated dependencies description: Check for outdated dependencies

View file

@ -1,7 +1,7 @@
/// An easily-extensible web server framework in Dart. /// An easily-extensible web server framework in Dart.
library platform_core; library platform_core;
export 'package:platform_exceptions/http_exception.dart'; export 'package:platform_support/exceptions.dart';
export 'package:platform_model/model.dart'; export 'package:platform_model/model.dart';
export 'package:platform_route/route.dart'; export 'package:platform_route/route.dart';
export 'src/core/core.dart'; export 'src/core/core.dart';

View file

@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io' show Cookie; import 'dart:io' show Cookie;
import 'package:platform_exceptions/http_exception.dart'; import 'package:platform_support/exceptions.dart';
import 'package:platform_route/route.dart'; import 'package:platform_route/route.dart';
import 'package:belatuk_combinator/belatuk_combinator.dart'; import 'package:belatuk_combinator/belatuk_combinator.dart';
import 'package:stack_trace/stack_trace.dart'; import 'package:stack_trace/stack_trace.dart';

View file

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:platform_exceptions/http_exception.dart'; import 'package:platform_support/exceptions.dart';
import 'service.dart'; import 'service.dart';

View file

@ -1,6 +1,6 @@
library angel_framework.http.metadata; library angel_framework.http.metadata;
import 'package:platform_exceptions/http_exception.dart'; import 'package:platform_support/exceptions.dart';
import 'hooked_service.dart' show HookedServiceEventListener; import 'hooked_service.dart' show HookedServiceEventListener;
import 'request_context.dart'; import 'request_context.dart';

View file

@ -4,7 +4,7 @@ import 'dart:async';
import 'dart:collection' show HashMap; import 'dart:collection' show HashMap;
import 'dart:convert'; import 'dart:convert';
import 'package:platform_container/container.dart'; import 'package:platform_container/container.dart';
import 'package:platform_exceptions/http_exception.dart'; import 'package:platform_support/exceptions.dart';
import 'package:platform_route/route.dart'; import 'package:platform_route/route.dart';
import 'package:belatuk_combinator/belatuk_combinator.dart'; import 'package:belatuk_combinator/belatuk_combinator.dart';
import 'package:http_parser/http_parser.dart'; import 'package:http_parser/http_parser.dart';

View file

@ -1,7 +1,7 @@
library platform_core.http.service; library platform_core.http.service;
import 'dart:async'; import 'dart:async';
import 'package:platform_exceptions/http_exception.dart'; import 'package:platform_support/exceptions.dart';
import 'package:belatuk_merge_map/belatuk_merge_map.dart'; import 'package:belatuk_merge_map/belatuk_merge_map.dart';
import 'package:quiver/core.dart'; import 'package:quiver/core.dart';
import '../util.dart'; import '../util.dart';

View file

@ -5,7 +5,7 @@ import 'package:platform_container/container.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:collection/collection.dart' show IterableExtension; import 'package:collection/collection.dart' show IterableExtension;
import 'package:http2/transport.dart'; import 'package:http2/transport.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
final RegExp _comma = RegExp(r',\s*'); final RegExp _comma = RegExp(r',\s*');

View file

@ -4,7 +4,7 @@ import 'dart:io';
import 'package:platform_core/core.dart' hide Header; import 'package:platform_core/core.dart' hide Header;
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:http2/transport.dart'; import 'package:http2/transport.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'http2_request_context.dart'; import 'http2_request_context.dart';
import 'http2_response_context.dart'; import 'http2_response_context.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';

View file

@ -389,20 +389,6 @@ packages:
relative: true relative: true
source: path source: path
version: "9.0.0" version: "9.0.0"
platform_exceptions:
dependency: "direct main"
description:
path: "../exceptions"
relative: true
source: path
version: "9.0.0"
platform_mocking:
dependency: "direct main"
description:
path: "../mocking"
relative: true
source: path
version: "9.0.0"
platform_model: platform_model:
dependency: "direct main" dependency: "direct main"
description: description:
@ -417,6 +403,20 @@ packages:
relative: true relative: true
source: path source: path
version: "9.0.0" version: "9.0.0"
platform_support:
dependency: "direct main"
description:
path: "../support"
relative: true
source: path
version: "9.0.0"
platform_testing:
dependency: "direct main"
description:
path: "../testing"
relative: true
source: path
version: "9.0.0"
pool: pool:
dependency: transitive dependency: transitive
description: description:

View file

@ -8,10 +8,10 @@ environment:
sdk: '>=3.3.0 <4.0.0' sdk: '>=3.3.0 <4.0.0'
dependencies: dependencies:
platform_container: ^9.0.0 platform_container: ^9.0.0
platform_exceptions: ^9.0.0
platform_model: ^9.0.0 platform_model: ^9.0.0
platform_route: ^9.0.0 platform_route: ^9.0.0
platform_mocking: ^9.0.0 platform_support: ^9.0.0
platform_testing: ^9.0.0
belatuk_merge_map: ^5.1.0 belatuk_merge_map: ^5.1.0
belatuk_combinator: ^5.2.0 belatuk_combinator: ^5.2.0
belatuk_http_server: ^4.4.0 belatuk_http_server: ^4.4.0

View file

@ -3,7 +3,7 @@ import 'dart:io';
import 'package:platform_container/mirrors.dart'; import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
final Uri endpoint = Uri.parse('http://example.com/accept'); final Uri endpoint = Uri.parse('http://example.com/accept');

View file

@ -3,7 +3,7 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {

View file

@ -6,7 +6,7 @@ import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'common.dart'; import 'common.dart';

View file

@ -1,7 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {

View file

@ -6,7 +6,7 @@ import 'package:platform_core/http.dart';
import 'package:platform_container/mirrors.dart'; import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'common.dart'; import 'common.dart';

View file

@ -6,7 +6,7 @@ import 'dart:typed_data' show BytesBuilder;
import 'package:platform_container/mirrors.dart'; import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
Future<List<int>> getBody(MockHttpResponse rs) async { Future<List<int>> getBody(MockHttpResponse rs) async {

View file

@ -2,7 +2,7 @@ import 'dart:async';
import 'package:platform_container/mirrors.dart'; import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
final Uri endpoint = Uri.parse('http://example.com'); final Uri endpoint = Uri.parse('http://example.com');

View file

@ -3,7 +3,7 @@ import 'dart:convert';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:http_parser/http_parser.dart'; import 'package:http_parser/http_parser.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {

View file

@ -4,7 +4,7 @@ import 'dart:convert';
import 'package:platform_container/mirrors.dart'; import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';

View file

@ -3,7 +3,7 @@ import 'dart:convert';
import 'package:platform_container/mirrors.dart'; import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';

View file

@ -4,7 +4,7 @@ import 'dart:io' show stderr;
import 'package:platform_container/mirrors.dart'; import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';

View file

@ -4,7 +4,7 @@ import 'dart:convert';
import 'package:platform_container/mirrors.dart'; import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {

View file

@ -5,7 +5,7 @@ import 'dart:io';
import 'package:platform_container/mirrors.dart'; import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';

View file

@ -6,7 +6,7 @@ import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart'; import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart'; import 'package:platform_core/http.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';

View file

@ -1,71 +0,0 @@
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
.dart_tool
.packages
.pub/
build/
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/
### Dart template
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
# SDK 1.20 and later (no longer creates packages directories)
# Older SDK versions
# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20)
.project
.buildlog
**/packages/
# Files created by dart2js
# (Most Dart developers will use pub build to compile Dart, use/modify these
# rules if you intend to use dart2js directly
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
# differentiate from explicit Javascript files)
*.dart.js
*.part.js
*.js.deps
*.js.map
*.info.json
# Directory created by dartdoc
# Don't commit pubspec lock file
# (Library packages only! Remove pattern if developing an application package)
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
## VsCode
.vscode/
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
.idea/
/out/
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

View file

@ -1,72 +0,0 @@
# Change Log
## 8.1.1
* Updated repository link
## 8.1.0
* Updated `lints` to 3.0.0
## 8.0.0
* Require Dart >= 3.0
## 7.0.0
* Require Dart >= 2.17
## 6.0.1
* Updated README
## 6.0.0
* Require Dart >= 2.16
* [**Breaking**] `error` for `HttpException` is no longer mandatory
## 5.0.0
* Skipped release
## 4.0.0
* Skipped release
## 3.1.0
* Upgraded to `lints` linter
## 3.0.2
* Updated LICENSE link
## 3.0.1
* Updated README
## 3.0.0
* Migrated to support Dart >= 2.12 NNBD
## 2.0.0
* Migrated to work with Dart >= 2.12 Non NNBD
## 1.1.0
* Emit `is_error` and `status_code` in `toJson()`.
* No more `camelCase` at all.
## 1.0.0+3
* Slightly relax the deserialization of `errors`.
## 1.0.0+2
* Added a backwards-compatible way to cast the `errors` List.
## 1.0.0+1
* Dart 2 updates.

View file

@ -1,8 +0,0 @@
# Protevus Http Exception
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/angel3_http_exception?include_prereleases)
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
[![License](https://img.shields.io/github/license/dart-backend/angel)](https://github.com/dart-backend/angel/tree/master/packages/http_exception/LICENSE)
Exception class that can be serialized to JSON and serialized to clients. Protevus's HTTP exception class.

View file

@ -1 +0,0 @@
include: package:lints/recommended.yaml

View file

@ -1,11 +0,0 @@
name: platform_exceptions
version: 9.0.0
description: Protevus Platform Exception package
homepage: https://protevus.com
documentation: https://docs.protevus.com
repository: https://git.protevus.com/protevus/platform/src/branch/main/packages/exceptions
environment:
sdk: '>=3.3.0 <4.0.0'
dev_dependencies:
lints: ^4.0.0
test: ^1.25.8

View file

@ -1,71 +0,0 @@
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
.dart_tool
.packages
.pub/
build/
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/
### Dart template
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
# SDK 1.20 and later (no longer creates packages directories)
# Older SDK versions
# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20)
.project
.buildlog
**/packages/
# Files created by dart2js
# (Most Dart developers will use pub build to compile Dart, use/modify these
# rules if you intend to use dart2js directly
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
# differentiate from explicit Javascript files)
*.dart.js
*.part.js
*.js.deps
*.js.map
*.info.json
# Directory created by dartdoc
# Don't commit pubspec lock file
# (Library packages only! Remove pattern if developing an application package)
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
## VsCode
.vscode/
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
.idea/
/out/
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

View file

@ -1,12 +0,0 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
Thomas is the current maintainer of the code base. He has refactored and migrated the
code base to support NNBD.
* __[Tobe O](thosakwe@gmail.com)__
Tobe has written much of the original code prior to NNBD migration. He has moved on and
is no longer involved with the project.

View file

@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2021, dukefirehawk.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1 +0,0 @@
include: package:lints/recommended.yaml

View file

@ -1,6 +0,0 @@
export 'src/connection_info.dart';
export 'src/headers.dart';
export 'src/lockable_headers.dart';
export 'src/request.dart';
export 'src/response.dart';
export 'src/session.dart';

View file

@ -1,25 +0,0 @@
name: platform_mocking
version: 9.0.0
description: Protevus Platform Mocking for dart:io HttpRequests, HttpResponses, HttpHeaders, etc.
homepage: https://protevus.com
documentation: https://docs.protevus.com
repository: https://git.protevus.com/protevus/platform/src/branch/main/packages/mocking
environment:
sdk: '>=3.3.0 <4.0.0'
dependencies:
charcode: ^1.3.1
dev_dependencies:
http: ^1.2.2
test: ^1.25.8
lints: ^4.0.0
# dependency_overrides:
# platform_core:
# path: ../framework
# platform_route:
# path: ../route
# platform_model:
# path: ../model
# platform_exceptions:
# path: ../exceptions
# platform_container:
# path: ../container/container

7
packages/support/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/
# Avoid committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock

View file

@ -0,0 +1,3 @@
## 1.0.0
- Initial version.

View file

@ -0,0 +1,39 @@
<!--
This README describes the package. If you publish this package to pub.dev,
this README's contents appear on the landing page for your package.
For information about how to write a good package README, see the guide for
[writing package pages](https://dart.dev/tools/pub/writing-package-pages).
For general information about developing packages, see the Dart guide for
[creating packages](https://dart.dev/guides/libraries/create-packages)
and the Flutter guide for
[developing packages and plugins](https://flutter.dev/to/develop-packages).
-->
TODO: Put a short description of the package here that helps potential users
know whether this package might be useful for them.
## Features
TODO: List what your package can do. Maybe include images, gifs, or videos.
## Getting started
TODO: List prerequisites and provide or point to information on how to
start using the package.
## Usage
TODO: Include short and useful examples for package users. Add longer examples
to `/example` folder.
```dart
const like = 'sample';
```
## Additional information
TODO: Tell users more about the package: where to find more information, how to
contribute to the package, how to file issues, what response they can expect
from the package authors, and more.

View file

@ -0,0 +1,30 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.
include: package:lints/recommended.yaml
# Uncomment the following section to specify additional rules.
# linter:
# rules:
# - camel_case_types
# analyzer:
# exclude:
# - path/to/excluded/files/**
# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options

View file

@ -1,4 +1,4 @@
import 'package:platform_exceptions/http_exception.dart'; import 'package:platform_support/src/exceptions/http_exception.dart';
void main() => void main() =>
throw PlatformHttpException.notFound(message: "Can't find that page!"); throw PlatformHttpException.notFound(message: "Can't find that page!");

View file

@ -0,0 +1,8 @@
/// Support for doing something awesome.
///
/// More dartdocs go here.
library;
export 'src/exceptions/http_exception.dart';
// TODO: Export any libraries intended for clients of this package.

View file

@ -0,0 +1,15 @@
name: platform_support
description: Protevus Platform support package.
version: 9.0.0
# repository: https://github.com/my_org/my_repo
environment:
sdk: ^3.5.4
# Add regular dependencies here.
dependencies:
# path: ^1.8.0
dev_dependencies:
lints: ^4.0.0
test: ^1.24.0

7
packages/testing/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/
# Avoid committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock

View file

@ -0,0 +1,30 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.
include: package:lints/recommended.yaml
# Uncomment the following section to specify additional rules.
# linter:
# rules:
# - camel_case_types
# analyzer:
# exclude:
# - path/to/excluded/files/**
# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options

View file

@ -1,5 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:platform_mocking/mocking.dart'; import 'package:platform_testing/http.dart';
Future<void> main() async { Future<void> main() async {
var rq = var rq =

Some files were not shown because too many files have changed in this diff Show more