[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\ncharset = utf-8\n\n[*.js]\nindent_style = space\nindent_size = 2\n\n[{package.json,*.yml,*.cjson}]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\n## Our Pledge\n\nThe **@usex/rule-engine** project is committed to fostering an open, welcoming, and inclusive community. As contributors and maintainers of this JSON-based rule engine, we pledge to make participation in our project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\nWe believe that a diverse community of developers, architects, and business analysts makes our rule engine better and more valuable for everyone.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n- **Inclusive Communication**: Using welcoming and inclusive language in issues, pull requests, and discussions\n- **Respectful Collaboration**: Being respectful of differing technical approaches, architectural decisions, and implementation strategies\n- **Constructive Feedback**: Gracefully accepting and providing constructive criticism on code, documentation, and rule engine design\n- **Community Focus**: Prioritizing what benefits the broader rule engine community and user ecosystem\n- **Empathy and Support**: Showing empathy towards other community members, especially when helping newcomers understand rule engine concepts\n- **Knowledge Sharing**: Actively sharing knowledge about business rules, JSON schemas, and engine optimization\n- **Technical Excellence**: Striving for high-quality code, comprehensive documentation, and robust testing\n\nExamples of unacceptable behavior by participants include:\n\n- **Harassment and Discrimination**: The use of sexualized language or imagery, trolling, insulting/derogatory comments, and personal or political attacks\n- **Privacy Violations**: Publishing others' private information, such as physical or electronic addresses, without explicit permission\n- **Technical Gatekeeping**: Deliberately making newcomers feel unwelcome or inferior based on their technical knowledge or experience level\n- **Destructive Criticism**: Providing criticism that is not constructive or that attacks the person rather than the idea or implementation\n- **Spam and Self-Promotion**: Excessive self-promotion, spam, or off-topic discussions unrelated to rule engines or the project\n- **Bad Faith Participation**: Contributing with malicious intent, deliberately introducing bugs, or sabotaging the project\n- **Violation of Licensing**: Misusing the project's MIT license or violating intellectual property rights\n- Other conduct which could reasonably be considered inappropriate in a professional open-source environment\n\n## Maintainer Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nThe maintainers of @usex/rule-engine have the right and responsibility to:\n\n- **Moderate Content**: Remove, edit, or reject comments, commits, code, documentation, wiki edits, issues, pull requests, and other contributions that are not aligned with this Code of Conduct\n- **Ensure Quality**: Maintain high standards for code quality, testing, and documentation while being supportive of contributors learning these standards\n- **Community Management**: Foster an inclusive environment where both technical experts and newcomers can contribute meaningfully to the rule engine ecosystem\n- **Enforcement Actions**: Take temporary or permanent action against contributors for behaviors deemed inappropriate, threatening, offensive, or harmful to the community\n- **Technical Leadership**: Guide the architectural direction of the rule engine while remaining open to community input and innovative ideas\n\n## Scope\n\nThis Code of Conduct applies within all @usex/rule-engine project spaces, including:\n\n- **GitHub Repository**: Issues, pull requests, discussions, code reviews, and wiki pages\n- **Documentation**: README files, API documentation, tutorials, and guides\n- **Communication Channels**: Official project communications via email, social media, or other platforms\n- **Community Events**: When representing the project at conferences, meetups, workshops, or online events\n- **Package Registries**: Comments and descriptions on npm, GitHub Packages, or other distribution platforms\n\nThis Code of Conduct also applies when community members are representing the rule engine project in public spaces. Representation may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainer:\n\n- **Primary Contact**: [Ali Torki](https://github.com/ali-master) via GitHub issues or discussions\n- **Direct Email**: For sensitive matters that require privacy\n\nAll complaints will be reviewed and investigated promptly and fairly. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. \n\n### Enforcement Process\n\n1. **Initial Review**: Reports will be acknowledged within 48 hours\n2. **Investigation**: Thorough review of the incident with all relevant parties\n3. **Resolution**: Appropriate action will be taken, which may include:\n   - Warning and education\n   - Temporary suspension from project spaces\n   - Permanent ban from the community\n4. **Follow-up**: Monitoring to ensure the resolution is effective\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by the project leadership.\n\n## Attribution\n\nThis Code of Conduct is customized for the **@usex/rule-engine** project and is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq\n\n---\n\n## Community Resources\n\n- 📚 **Documentation**: [Project README](../README.md)\n- 🐛 **Report Issues**: [GitHub Issues](https://github.com/ali-master/rule-engine/issues)\n- 💬 **Discussions**: [GitHub Discussions](https://github.com/ali-master/rule-engine/discussions)\n- 📦 **NPM Package**: [@usex/rule-engine](https://www.npmjs.com/package/@usex/rule-engine)\n\n**Thank you for helping make the @usex/rule-engine community welcoming and inclusive for everyone!** 🚀\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: ci\n\non:\n  pull_request:\n    branches:\n      - master\n      - develop\n  push:\n    branches:\n      - master\n      - develop\n\njobs:\n  lint:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n      - run: npm i -g --force corepack && corepack enable\n      - uses: actions/setup-node@v4\n        with:\n          node-version: lts/*\n          cache: pnpm\n\n      - name: 📦 Install dependencies\n        run: pnpm install\n\n      - name: 🛠 Build project\n        run: pnpm build\n\n      - name: 🔠 Lint project\n        run: pnpm lint\n\n  test:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n      - run: npm i -g --force corepack && corepack enable\n      - uses: actions/setup-node@v4\n        with:\n          node-version: lts/*\n          cache: pnpm\n\n      - name: 📦 Install dependencies\n        run: pnpm install\n\n      - name: 🛠 Build project\n        run: pnpm build\n\n      - name: 💪 Test types\n        run: pnpm test:types\n\n      - name: 🧪 Test project\n        run: pnpm test:coverage\n\n      - name: 📊 Generate test report\n        if: always()\n        run: pnpm test:junit\n\n      - name: 📈 Upload test results to Codecov\n        if: ${{ !cancelled() }}\n        uses: codecov/test-results-action@v1\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n\n      - name: 🟩 Coverage\n        uses: codecov/codecov-action@v5\n        env:\n          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "**/dist\n**/node_modules\n**/coverage\n.vscode\n.DS_Store\n.eslintcache\n*.log*\n**/*.env*\n.husky\n.claude\napps/*/.next/\n"
  },
  {
    "path": ".idea/.gitignore",
    "content": "# Default ignored files\n/shelf/\n/workspace.xml\n# Datasource local storage ignored files\n/dataSources/\n/dataSources.local.xml\n"
  },
  {
    "path": ".idea/compiler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"TypeScriptCompiler\">\n    <option name=\"useTypesFromServer\" value=\"true\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/git_toolbox_prj.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GitToolBoxProjectSettings\">\n    <option name=\"commitMessageIssueKeyValidationOverride\">\n      <BoolValueOverride>\n        <option name=\"enabled\" value=\"true\" />\n      </BoolValueOverride>\n    </option>\n    <option name=\"commitMessageValidationEnabledOverride\">\n      <BoolValueOverride>\n        <option name=\"enabled\" value=\"true\" />\n      </BoolValueOverride>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/inspectionProfiles/Project_Default.xml",
    "content": "<component name=\"InspectionProjectProfileManager\">\n  <profile version=\"1.0\">\n    <option name=\"myName\" value=\"Project Default\" />\n    <inspection_tool class=\"Eslint\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\" />\n  </profile>\n</component>"
  },
  {
    "path": ".idea/jsLinters/eslint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"EslintConfiguration\">\n    <option name=\"fix-on-save\" value=\"true\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/usex.iml\" filepath=\"$PROJECT_DIR$/.idea/usex.iml\" />\n    </modules>\n  </component>\n</project>"
  },
  {
    "path": ".idea/prettier.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"PrettierConfiguration\">\n    <option name=\"myConfigurationMode\" value=\"AUTOMATIC\" />\n    <option name=\"myRunOnSave\" value=\"true\" />\n    <option name=\"myFilesPattern\" value=\"**/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts,vue,astro,json,css}\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/usex.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"WEB_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\">\n    <content url=\"file://$MODULE_DIR$\">\n      <excludeFolder url=\"file://$MODULE_DIR$/.tmp\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/temp\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/tmp\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/apps/web/.next\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/packages/builder/dist-demo\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": ".npmignore",
    "content": "# Ignore everything by default\n*\n\n# Include the dist folder and its contents\n!dist\n!dist/**\n\n# Exclude .tsbuildinfo files (not needed in published package)\ndist/**/*.tsbuildinfo\n\n# Include the assets folder and its contents\n!assets\n!assets/**\n"
  },
  {
    "path": ".npmrc",
    "content": "strict-peer-dependencies=false\n\n"
  },
  {
    "path": ".nvmrc",
    "content": "24.4.1\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [ali_4286@live.com](mailto:ali_4286@live.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to @usex/rule-engine\n\nFirst off, thank you for considering contributing to @usex/rule-engine! It's people like you that make this project better for everyone.\n\n## Table of Contents\n\n- [Code of Conduct](#code-of-conduct)\n- [Getting Started](#getting-started)\n- [Development Setup](#development-setup)\n- [How to Contribute](#how-to-contribute)\n- [Coding Standards](#coding-standards)\n- [Testing](#testing)\n- [Documentation](#documentation)\n- [Pull Request Process](#pull-request-process)\n\n## Code of Conduct\n\nThis project and everyone participating in it is governed by our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.\n\n## Getting Started\n\n1. Fork the repository on GitHub\n2. Clone your fork locally\n3. Set up the development environment\n4. Create a branch for your changes\n5. Make your changes\n6. Submit a pull request\n\n## Development Setup\n\n### Prerequisites\n\n- Node.js >= 18.12.0\n- pnpm >= 10.11.0\n\n### Installation\n\n```bash\n# Clone your fork\ngit clone https://github.com/YOUR_USERNAME/rule-engine.git\ncd rule-engine\n\n# Install dependencies\npnpm install\n\n# Build all packages\npnpm build\n```\n\n### Project Structure\n\n```\nrule-engine/\n├── packages/\n│   ├── core/         # Core rule engine library\n│   └── builder/      # Visual rule builder UI\n├── apps/\n│   └── web/          # Documentation website\n└── docs/             # Additional documentation\n```\n\n## How to Contribute\n\n### Reporting Bugs\n\nBefore creating bug reports, please check existing issues. When creating a bug report, include:\n\n1. **Clear title and description**\n2. **Steps to reproduce**\n3. **Expected behavior**\n4. **Actual behavior**\n5. **Code samples** (if applicable)\n6. **Environment details** (Node version, OS, etc.)\n\n### Suggesting Features\n\nFeature suggestions are welcome! Please:\n\n1. **Check existing issues** first\n2. **Provide clear use cases**\n3. **Explain the benefits**\n4. **Consider implementation details**\n\n### Code Contributions\n\n1. **Small changes**: Bug fixes, documentation updates\n2. **Large changes**: New features, significant refactoring (discuss first in an issue)\n\n## Coding Standards\n\n### TypeScript\n\n- Use TypeScript for all new code\n- Enable strict mode\n- Provide proper types (avoid `any`)\n- Document complex types\n\n### Code Style\n\n```typescript\n// Good\nexport function evaluateRule<T>(\n  rule: RuleType<T>,\n  data: unknown\n): Promise<EvaluationResult<T>> {\n  // Implementation\n}\n\n// Bad\nexport function evaluateRule(rule: any, data: any): any {\n  // Implementation\n}\n```\n\n### Naming Conventions\n\n- **Files**: kebab-case (e.g., `rule-engine.ts`)\n- **Classes**: PascalCase (e.g., `RuleEngine`)\n- **Functions/Variables**: camelCase (e.g., `evaluateRule`)\n- **Constants**: UPPER_SNAKE_CASE (e.g., `MAX_DEPTH`)\n- **Types/Interfaces**: PascalCase (e.g., `RuleType`)\n\n### Comments\n\n```typescript\n/**\n * Evaluates a rule against the provided criteria.\n * \n * @param rule - The rule to evaluate\n * @param criteria - The data to evaluate against\n * @param trustRule - Skip validation if true\n * @returns The evaluation result\n * \n * @example\n * ```typescript\n * const result = await evaluateRule(rule, { age: 25 });\n * ```\n */\n```\n\n## Testing\n\n### Running Tests\n\n```bash\n# Run all tests\npnpm test\n\n# Run tests in watch mode\npnpm test:watch\n\n# Run tests with coverage\npnpm test:coverage\n\n# Run specific package tests\ncd packages/core && pnpm test\n```\n\n### Writing Tests\n\n```typescript\ndescribe('RuleEngine', () => {\n  describe('evaluate', () => {\n    it('should evaluate simple rule correctly', async () => {\n      const rule = {\n        conditions: {\n          and: [\n            { field: 'age', operator: 'greater-than', value: 18 }\n          ]\n        }\n      };\n      \n      const result = await RuleEngine.evaluate(rule, { age: 25 });\n      \n      expect(result.isPassed).toBe(true);\n      expect(result.value).toBe(true);\n    });\n  });\n});\n```\n\n### Test Requirements\n\n- Write tests for all new features\n- Maintain or improve code coverage\n- Test edge cases\n- Include integration tests for complex features\n\n## Documentation\n\n### Code Documentation\n\n- Document all public APIs\n- Include JSDoc comments\n- Provide usage examples\n- Explain complex algorithms\n\n### README Updates\n\nUpdate relevant README files when:\n- Adding new features\n- Changing APIs\n- Adding new operators\n- Fixing significant bugs\n\n### Documentation Structure\n\n```\npackages/core/\n├── README.md           # Package documentation\n└── docs/\n    ├── api-reference.md\n    ├── operators.md\n    └── best-practices.md\n```\n\n## Pull Request Process\n\n### Before Submitting\n\n1. **Update documentation** for any API changes\n2. **Add tests** for new functionality\n3. **Run all tests** locally\n4. **Update CHANGELOG** if applicable\n5. **Ensure code follows** style guidelines\n\n### PR Guidelines\n\n#### Title Format\n```\n<type>(<scope>): <subject>\n\nExamples:\nfeat(core): add new date-between operator\nfix(builder): resolve focus issue in field selector\ndocs(core): update migration guide\n```\n\n#### Types\n- `feat`: New feature\n- `fix`: Bug fix\n- `docs`: Documentation only\n- `style`: Code style changes\n- `refactor`: Code refactoring\n- `perf`: Performance improvements\n- `test`: Test additions/changes\n- `chore`: Maintenance tasks\n\n#### Description Template\n```markdown\n## Description\nBrief description of changes\n\n## Motivation\nWhy these changes are needed\n\n## Changes\n- Change 1\n- Change 2\n\n## Testing\nHow the changes were tested\n\n## Breaking Changes\nList any breaking changes\n\n## Related Issues\nFixes #123\n```\n\n### Review Process\n\n1. **Automated checks** must pass\n2. **Code review** by maintainers\n3. **Address feedback** promptly\n4. **Squash commits** if requested\n\n## Questions?\n\nFeel free to:\n- Open an issue for questions\n- Join discussions in existing issues\n- Contact maintainers\n\nThank you for contributing! 🎉"
  },
  {
    "path": "LICENCE",
    "content": "MIT License\n\nCopyright (c) 2022 Ali Torki\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n  <img src=\"./assets/core-logo.png\" alt=\"Rule Engine\" width=\"120\" />\n\n  <h1>@usex/rule-engine</h1>\n  <p><strong>🎯 The Ultimate JSON-Based Rule Engine for Modern Applications</strong></p>\n\n  <p>\n    <a href=\"https://www.npmjs.com/package/@usex/rule-engine\"><img src=\"https://img.shields.io/npm/v/@usex/rule-engine?style=flat-square&color=blue\" alt=\"npm version\" /></a>\n    <a href=\"https://github.com/ali-master/rule-engine/blob/master/LICENSE\"><img src=\"https://img.shields.io/npm/l/@usex/rule-engine?style=flat-square&color=green\" alt=\"license\" /></a>\n    <a href=\"https://codecov.io/gh/ali-master/rule-engine\"><img src=\"https://codecov.io/gh/ali-master/rule-engine/graph/badge.svg?token=UN5opqxNsi\" alt=\"codecov\" /></a>\n    <a href=\"https://www.npmjs.com/package/@usex/rule-engine\"><img src=\"https://img.shields.io/npm/dm/@usex/rule-engine?style=flat-square&color=orange\" alt=\"downloads\" /></a>\n    <a href=\"https://github.com/ali-master/rule-engine\"><img src=\"https://img.shields.io/github/stars/ali-master/rule-engine?style=flat-square&color=yellow\" alt=\"stars\" /></a>\n    <a href=\"https://bundlephobia.com/package/@usex/rule-engine\"><img src=\"https://img.shields.io/bundlephobia/minzip/@usex/rule-engine?style=flat-square&color=purple\" alt=\"bundle size\" /></a>\n  </p>\n\n  <p>\n    <a href=\"#-quick-start\">Quick Start</a> •\n    <a href=\"#-packages\">Packages</a> •\n    <a href=\"#-examples\">Examples</a> •\n    <a href=\"#-documentation\">Documentation</a> •\n    <a href=\"#-why-choose-this\">Why This?</a>\n  </p>\n\n<a href=\"https://www.producthunt.com/products/open-source-rule-engine?embed=true&utm_source=badge-featured&utm_medium=badge&utm_source=badge-open&#0045;source&#0045;rule&#0045;engine\" target=\"_blank\"><img src=\"https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1012148&theme=light&t=1759345778417\" alt=\"Open&#0032;Source&#0032;Rule&#0032;Engine - A&#0032;JSON&#0032;rule&#0032;engine&#0032;for&#0032;declarative&#0032;business&#0032;logic&#0046; | Product Hunt\" style=\"width: 250px; height: 54px;\" width=\"250\" height=\"54\" /></a>\n</div>\n\n---\n\n**Transform complex business logic into elegant, maintainable JSON rules.** Stop hardcoding decisions, start building intelligent systems that adapt to your business needs.\n\n```typescript\n// From this mess...\nif (user.tier === 'vip' && order.total > 100 && user.country === 'US') {\n  return { discount: 0.20, shipping: 'free' };\n} else if (user.isNew && order.total > 50) {\n  return { discount: 0.10, shipping: 'standard' };\n} // ... 50 more lines of spaghetti code\n\n// To this elegance...\nconst result = await RuleEngine.evaluate(discountRules, { user, order });\n```\n\n## 🚀 Why Rule Engine?\n\n### **Built for Modern Developers**\n- 🎯 **Zero Dependencies** - Pure JavaScript excellence, no supply chain bloat\n- 🏎️ **Lightning Fast** - 17,000+ rule evaluations per second with complex JSONPath support at 55,000+ ops/sec\n- 🛡️ **TypeScript Native** - **Fully typed with generic support** for bulletproof type safety\n- 🔧 **Extensible Architecture** - **Create & register custom operators** without core modifications\n- 🌐 **Universal** - Node.js, browsers, edge functions, Deno, Bun everywhere\n\n### **Powerful Yet Intuitive**\n- 🔍 **JSONPath Support** - Navigate complex objects: `$.user.profile.settings.theme`\n- 🔗 **Self-Referencing** - Dynamic field references: `\"value\": \"$.maxPrice\"`\n- 🧩 **121+ Operators** - From basic comparisons to advanced pattern matching\n- 🏗️ **Visual Builder** - Drag-and-drop UI for non-technical stakeholders\n\n### **Enterprise Ready**\n- 🔧 **Extensible Core** - **Plugin custom operators** without touching internals\n- 🛡️ **Type-Safe APIs** - **Generic interfaces** ensure compile-time safety\n- 📊 **Rule Introspection** - Reverse-engineer possible inputs from rule definitions\n- ⚡ **Performance Optimized** - Optional validation bypass for trusted rules\n- 🎭 **Data Mutations** - Preprocess data before evaluation\n\n## 📦 Packages\n\nThis monorepo contains two powerful packages:\n\n| Package | Description | Install |\n|---------|-------------|---------|\n| **[@usex/rule-engine](./packages/core)** <br/> [![npm](https://img.shields.io/npm/v/@usex/rule-engine.svg?style=flat-square)](https://www.npmjs.com/package/@usex/rule-engine) | **Fully typed** core engine with **generic support** & **custom operators** | `npm install @usex/rule-engine` |\n| **[@usex/rule-engine-builder](./packages/builder)** <br/> [![npm](https://img.shields.io/npm/v/@usex/rule-engine-builder.svg?style=flat-square)](https://www.npmjs.com/package/@usex/rule-engine-builder) | Visual rule builder for React applications | `npm install @usex/rule-engine-builder` |\n\n## 🛡️ TypeScript Excellence & Extensibility\n\n### **Fully Typed with Generics**\nThe core package is built with TypeScript-first design, providing complete type safety:\n\n```typescript\n// Type-safe rule definitions with generics\ninterface DiscountResult {\n  discount: number;\n  code: string;\n  description: string;\n}\n\n// Generic rule with full type inference\nconst discountRule: Rule<DiscountResult> = {\n  conditions: [\n    {\n      and: [\n        { field: \"$.user.tier\", operator: \"equals\", value: \"premium\" },\n        { field: \"$.order.total\", operator: \"greater-than\", value: 100 }\n      ],\n      result: {\n        discount: 0.20,      // ✅ Type-safe\n        code: \"PREMIUM20\",   // ✅ Type-safe\n        description: \"20% premium discount\"  // ✅ Type-safe\n      }\n    }\n  ],\n  default: { discount: 0, code: \"\", description: \"No discount\" }\n};\n\n// Evaluation with full type inference\nconst result = await RuleEngine.evaluate<DiscountResult>(discountRule, orderData);\n// result.value is automatically typed as DiscountResult ✅\n```\n\n### **Custom Operators Made Easy**\nExtend the engine with your business-specific logic:\n\n```typescript\nimport { OperatorRegistry, BaseOperator } from '@usex/rule-engine';\n\n// 1. Create your custom operator\nclass IsWeekendOperator extends BaseOperator {\n  name = 'is-weekend';\n  category = 'datetime';\n\n  evaluate(fieldValue: Date): boolean {\n    const day = fieldValue.getDay();\n    return day === 0 || day === 6; // Sunday or Saturday\n  }\n}\n\nclass BulkDiscountEligibleOperator extends BaseOperator {\n  name = 'bulk-discount-eligible';\n  category = 'business';\n\n  evaluate(orderData: any, threshold: number): boolean {\n    return orderData.quantity >= threshold || orderData.value >= threshold * 10;\n  }\n}\n\n// 2. Register your operators\nOperatorRegistry.register(new IsWeekendOperator());\nOperatorRegistry.register(new BulkDiscountEligibleOperator());\n\n// 3. Use them in your rules immediately\nconst weekendRule = {\n  conditions: {\n    and: [\n      { field: \"$.currentDate\", operator: \"is-weekend\", value: true },\n      { field: \"$.order\", operator: \"bulk-discount-eligible\", value: 10 }\n    ],\n    result: {\n      discount: 0.25,\n      reason: \"Weekend bulk discount!\"\n    }\n  }\n};\n\n// 4. Full TypeScript support for your custom operators\nconst result = await RuleEngine.evaluate(weekendRule, {\n  currentDate: new Date(),\n  order: { quantity: 15, value: 200 }\n}); // ✅ Fully typed, including custom operators\n```\n\n### **Advanced Generic Usage**\n\n```typescript\n// Define complex result types\ninterface AccessControlResult {\n  allowed: boolean;\n  permissions: string[];\n  level: 'admin' | 'user' | 'guest';\n  expiresAt?: Date;\n}\n\ninterface UserData {\n  role: string;\n  department: string;\n  clearanceLevel: number;\n}\n\n// Generic rule with both input and output types\nconst accessRule: Rule<AccessControlResult, UserData> = {\n  conditions: [\n    {\n      and: [\n        { field: \"role\", operator: \"equals\", value: \"admin\" },\n        { field: \"clearanceLevel\", operator: \"greater-than\", value: 5 }\n      ],\n      result: {\n        allowed: true,\n        permissions: [\"read\", \"write\", \"delete\"],\n        level: \"admin\"\n      }\n    }\n  ],\n  default: {\n    allowed: false,\n    permissions: [],\n    level: \"guest\"\n  }\n};\n\n// Type-safe evaluation with input validation\nconst userData: UserData = {\n  role: \"admin\",\n  department: \"engineering\",\n  clearanceLevel: 8\n};\n\nconst access = await RuleEngine.evaluate<AccessControlResult, UserData>(\n  accessRule,\n  userData\n);\n// Both input and output are fully typed ✅\n```\n\n## 🎬 Quick Start\n\n### Core Engine (Pure JavaScript/TypeScript)\n\n```bash\nnpm install @usex/rule-engine\n```\n\n```typescript\nimport { RuleEngine } from '@usex/rule-engine';\n\n// Define a discount rule\nconst discountRule = {\n  conditions: [\n    {\n      // VIP customers get 20% off orders over $100\n      and: [\n        { field: \"$.customer.tier\", operator: \"equals\", value: \"vip\" },\n        { field: \"$.order.total\", operator: \"greater-than\", value: 100 }\n      ],\n      result: { discount: 0.20, message: \"VIP discount applied! 🎉\" }\n    },\n    {\n      // First-time buyers get 10% off orders over $50\n      and: [\n        { field: \"$.customer.orderCount\", operator: \"equals\", value: 0 },\n        { field: \"$.order.total\", operator: \"greater-than\", value: 50 }\n      ],\n      result: { discount: 0.10, message: \"Welcome! First order discount 🎁\" }\n    }\n  ],\n  default: { discount: 0, message: \"No discount available\" }\n};\n\n// Apply the rule\nconst orderData = {\n  customer: { tier: \"vip\", orderCount: 5 },\n  order: { total: 150, items: [\"laptop\", \"mouse\"] }\n};\n\nconst result = await RuleEngine.evaluate(discountRule, orderData);\nconsole.log(result);\n// { value: { discount: 0.20, message: \"VIP discount applied! 🎉\" }, isPassed: true }\n```\n\n### Visual Builder (React Applications)\n\n```bash\nnpm install @usex/rule-engine-builder @usex/rule-engine react\n```\n\n```tsx\nimport React, { useState } from 'react';\nimport { RuleBuilder } from '@usex/rule-engine-builder';\nimport { RuleEngine } from '@usex/rule-engine';\n\nfunction App() {\n  const [rule, setRule] = useState(null);\n\n  const availableFields = [\n    { name: '$.user.tier', type: 'string', label: 'User Tier' },\n    { name: '$.user.age', type: 'number', label: 'User Age' },\n    { name: '$.order.total', type: 'number', label: 'Order Total' },\n    { name: '$.order.items', type: 'array', label: 'Order Items' }\n  ];\n\n  const testData = {\n    user: { tier: 'premium', age: 28 },\n    order: { total: 150, items: ['laptop', 'mouse'] }\n  };\n\n  return (\n    <div className=\"app\">\n      <h1>Build Your Business Rules Visually</h1>\n\n      <RuleBuilder\n        rule={rule}\n        onRuleChange={setRule}\n        availableFields={availableFields}\n        testData={testData}\n        theme=\"auto\"\n        showPreview={true}\n        showHistory={true}\n      />\n\n      {rule && (\n        <button onClick={async () => {\n          const result = await RuleEngine.evaluate(rule, testData);\n          console.log('Rule Result:', result);\n        }}>\n          Test Rule\n        </button>\n      )}\n    </div>\n  );\n}\n```\n\n## 💡 Real-World Examples\n\n### 🛒 E-commerce Pricing Engine\n\n```typescript\nconst pricingRules = {\n  conditions: [\n    {\n      // Black Friday: 50% off everything\n      and: [\n        { field: \"$.event.name\", operator: \"equals\", value: \"black-friday\" },\n        { field: \"$.event.active\", operator: \"equals\", value: true }\n      ],\n      result: { discount: 0.50, code: \"BLACKFRIDAY50\", expires: \"2025-11-30T23:59:59Z\" }\n    },\n    {\n      // Bulk orders: tiered discounts\n      or: [\n        { field: \"$.cart.quantity\", operator: \"greater-than\", value: 50 },\n        { field: \"$.cart.value\", operator: \"greater-than\", value: 1000 }\n      ],\n      result: { discount: 0.15, code: \"BULK15\", shipping: \"free\" }\n    },\n    {\n      // New customer welcome\n      and: [\n        { field: \"$.customer.orderHistory.length\", operator: \"equals\", value: 0 },\n        { field: \"$.cart.value\", operator: \"greater-than\", value: 50 }\n      ],\n      result: { discount: 0.10, code: \"WELCOME10\", message: \"Welcome! Enjoy 10% off your first order 🎉\" }\n    }\n  ],\n  default: { discount: 0, message: \"Regular pricing applies\" }\n};\n```\n\n### 🔐 Dynamic Access Control\n\n```typescript\nconst accessControlRules = {\n  conditions: [\n    {\n      // Super admin: full access\n      and: [\n        { field: \"role\", operator: \"equals\", value: \"super-admin\" },\n        { field: \"status\", operator: \"equals\", value: \"active\" }\n      ],\n      result: {\n        permissions: [\"read\", \"write\", \"delete\", \"admin\"],\n        level: \"unlimited\",\n        expires: null\n      }\n    },\n    {\n      // Department manager: departmental access during business hours\n      and: [\n        { field: \"role\", operator: \"equals\", value: \"manager\" },\n        { field: \"department\", operator: \"exists\", value: true },\n        { field: \"$.currentTime\", operator: \"time-between\", value: [\"09:00\", \"17:00\"] }\n      ],\n      result: {\n        permissions: [\"read\", \"write\"],\n        level: \"department\",\n        scope: \"$.department\",\n        expires: \"$.session.loginTime + 8h\"\n      }\n    }\n  ],\n  default: { permissions: [], level: \"none\", message: \"Access denied\" }\n};\n```\n\n### ✅ Smart Form Validation\n\n```typescript\nconst registrationValidation = {\n  conditions: {\n    and: [\n      // Email validation\n      {\n        field: \"email\",\n        operator: \"email\",\n        value: true,\n        message: \"Please enter a valid email address\"\n      },\n      // Strong password requirements\n      {\n        and: [\n          {\n            field: \"password\",\n            operator: \"min-length\",\n            value: 8,\n            message: \"Password must be at least 8 characters long\"\n          },\n          {\n            field: \"password\",\n            operator: \"matches\",\n            value: \".*[A-Z].*\",\n            message: \"Password must contain at least one uppercase letter\"\n          },\n          {\n            field: \"password\",\n            operator: \"matches\",\n            value: \".*[0-9].*\",\n            message: \"Password must contain at least one number\"\n          }\n        ]\n      },\n      // Age verification\n      {\n        field: \"birthDate\",\n        operator: \"date-before\",\n        value: \"$.today - 18 years\",\n        message: \"You must be 18 or older to register\"\n      }\n    ]\n  }\n};\n```\n\n## 🔧 Advanced Features\n\n### 🔗 Self-Referencing Magic\nCompare fields against other fields dynamically:\n\n```typescript\nconst budgetRule = {\n  conditions: {\n    and: [\n      // Actual cost must not exceed budget\n      {\n        field: \"$.project.actualCost\",\n        operator: \"less-than-or-equals\",\n        value: \"$.project.approvedBudget\"\n      },\n      // Start date must be before end date\n      {\n        field: \"$.project.startDate\",\n        operator: \"date-before\",\n        value: \"$.project.endDate\"\n      }\n    ]\n  }\n};\n```\n\n### 🏗️ Fluent Builder Pattern\nConstruct complex rules programmatically:\n\n```typescript\nconst complexRule = RuleEngine.builder()\n  .add({\n    and: [\n      { field: \"userType\", operator: \"equals\", value: \"premium\" },\n      { field: \"subscriptionActive\", operator: \"equals\", value: true }\n    ],\n    result: { access: \"premium\", features: [\"analytics\", \"api\", \"support\"] }\n  })\n  .add({\n    and: [\n      { field: \"userType\", operator: \"equals\", value: \"basic\" },\n      { field: \"trialExpired\", operator: \"equals\", value: false }\n    ],\n    result: { access: \"basic\", features: [\"dashboard\"] }\n  })\n  .default({ access: \"none\", features: [] })\n  .build(true); // Validate during build\n```\n\n### 📊 Rule Introspection\nUnderstand what your rules need:\n\n```typescript\nconst insights = RuleEngine.introspect(complexRule);\nconsole.log(insights);\n// {\n//   fields: [\"userType\", \"subscriptionActive\", \"trialExpired\"],\n//   operators: [\"equals\"],\n//   possibleResults: [\n//     { access: \"premium\", features: [\"analytics\", \"api\", \"support\"] },\n//     { access: \"basic\", features: [\"dashboard\"] },\n//     { access: \"none\", features: [] }\n//   ],\n//   complexity: \"medium\",\n//   estimatedPerformance: \"fast\"\n// }\n```\n\n## 🏎️ Performance & Benchmarks\n*Real-world performance data from actual benchmark runs (10,000 iterations each)*\n\n### Core Rule Performance\n| Operation | Hz (ops/sec) | Avg Time | Performance Grade |\n|-----------|-------------|----------|-------------------|\n| **Simple Rules (3-5 conditions)** | **~16,900** | **0.059ms** | **🚀 Lightning Fast** |\n| Complex Rules (nested evaluation) | ~17,400 | 0.057ms | 🔥 Blazing |\n| Complex Rules (priority-based) | ~8,000 | 0.126ms | ⚡ Very Fast |\n| Array Operations | ~45,400 | 0.022ms | 🚀 Ultra Fast |\n\n### Advanced Features\n| Feature | Hz (ops/sec) | Avg Time | Performance Grade |\n|---------|-------------|----------|-------------------|\n| **JSONPath Resolution (simple)** | **~55,000** | **0.018ms** | **🔥 Blazing Fast** |\n| JSONPath Deep Nested Access | ~54,000 | 0.019ms | 🔥 Blazing Fast |\n| JSONPath Array Processing | ~49,500 | 0.020ms | 🚀 Ultra Fast |\n| Self-Referencing (complex) | ~33,600 | 0.030ms | 🚀 Excellent |\n| Data Mutations (simple) | ~16,300 | 0.061ms | 🚀 Fast |\n| Data Mutations (complex) | ~34,100 | 0.029ms | 🚀 Excellent |\n\n### Specialized Operations\n| Operation | Hz (ops/sec) | Use Case | Performance |\n|-----------|-------------|----------|-------------|\n| **Rule Builder (simple)** | **~12,000,000** | Rule Construction | ⚡ Instant |\n| Rule Builder (complex) | ~94,300 | Complex Rule Building | 🚀 Very Fast |\n| Rule Validation | ~67,000 | Schema Validation | 🔥 Blazing |\n| Error Handling | ~1,661,000 | Exception Processing | ⚡ Instant |\n\n### Optimization Tips\n\n1. **Trust Mode**: Skip validation for 20% performance boost\n   ```typescript\n   const result = await RuleEngine.evaluate(rule, data, true);\n   ```\n\n2. **Batch Processing**: Process multiple records at once\n   ```typescript\n   const results = await RuleEngine.evaluate(rule, arrayOfData);\n   ```\n\n3. **Operator Selection**: Prefer specific operators over general ones\n   ```typescript\n   { operator: \"equals\" }        // ✅ Fast\n   { operator: \"matches\" }       // ⚠️ Slower for simple cases\n   ```\n\n## 🔧 Operator Categories\n\n### All 121+ Operators at Your Fingertips\n\n| Category | Count | Examples |\n|----------|-------|----------|\n| **Comparison** | 6 | `equals`, `greater-than`, `less-than` |\n| **String** | 12 | `like`, `starts-with`, `matches` |\n| **Numeric** | 11 | `between`, `divisible-by`, `even` |\n| **Array** | 12 | `contains`, `contains-any`, `array-length` |\n| **Date/Time** | 14 | `date-after`, `date-between`, `time-equals` |\n| **Type** | 10 | `string`, `number`, `boolean` |\n| **Existence** | 6 | `exists`, `empty`, `null-or-undefined` |\n| **Boolean** | 4 | `truthy`, `falsy`, `boolean-string` |\n| **Pattern** | 2 | `matches`, `not-matches` |\n| **Length** | 8 | `min-length`, `max-length`, `length-between` |\n| **Persian** | 6 | `persian-alpha`, `persian-number` |\n| **Validation** | 30+ | `email`, `url`, `uuid`, `alpha-numeric` |\n\n### Popular Operators\n\n```typescript\n// String operations\n{ field: \"name\", operator: \"equals\", value: \"John\" }\n{ field: \"email\", operator: \"like\", value: \"*@gmail.com\" }\n{ field: \"description\", operator: \"matches\", value: \"^Product.*\" }\n\n// Numeric comparisons\n{ field: \"age\", operator: \"greater-than\", value: 18 }\n{ field: \"price\", operator: \"between\", value: [10, 100] }\n\n// Array operations\n{ field: \"roles\", operator: \"contains\", value: \"admin\" }\n{ field: \"tags\", operator: \"contains-all\", value: [\"urgent\", \"review\"] }\n\n// Date/time\n{ field: \"expiryDate\", operator: \"date-before-now\", value: true }\n{ field: \"openTime\", operator: \"time-after\", value: \"09:00\" }\n\n// Validation\n{ field: \"email\", operator: \"email\", value: true }\n{ field: \"password\", operator: \"min-length\", value: 8 }\n```\n\n## 🎓 Complete TypeScript Excellence\n\n### **Built-in Generic Support**\nThe core package is **100% TypeScript** with comprehensive generic interfaces:\n\n```typescript\n// 🛡️ Full generic support for input and output types\ninterface UserPermissions {\n  canRead: boolean;\n  canWrite: boolean;\n  canDelete: boolean;\n  level: 'admin' | 'user' | 'guest';\n}\n\ninterface UserContext {\n  role: string;\n  department: string;\n  active: boolean;\n}\n\n// ✅ Type-safe rule with both input/output generics\nconst accessRule: Rule<UserPermissions, UserContext> = {\n  conditions: [\n    {\n      and: [\n        { field: \"role\", operator: \"equals\", value: \"admin\" },\n        { field: \"active\", operator: \"equals\", value: true }\n      ],\n      result: {\n        canRead: true,\n        canWrite: true,\n        canDelete: true,\n        level: \"admin\"   // ✅ Autocomplete & validation\n      }\n    }\n  ],\n  default: {\n    canRead: false,\n    canWrite: false,\n    canDelete: false,\n    level: \"guest\"     // ✅ Type-safe default\n  }\n};\n\n// ✅ Fully typed evaluation with IntelliSense\nconst result = await RuleEngine.evaluate<UserPermissions, UserContext>(\n  accessRule,\n  { role: \"admin\", department: \"IT\", active: true }\n);\n// result.value is automatically typed as UserPermissions with full IDE support ✅\n```\n\n### **Type-Safe Custom Operators**\nCustom operators inherit full TypeScript support:\n\n```typescript\n// ✅ Typed custom operator interface\ninterface CustomOperator<T = any, V = any> {\n  name: string;\n  category: string;\n  evaluate(fieldValue: T, operatorValue: V): boolean;\n}\n\n// ✅ Type-safe custom operator implementation\nclass DateRangeOperator implements CustomOperator<Date, [Date, Date]> {\n  name = 'date-within-range';\n  category = 'datetime';\n\n  evaluate(fieldValue: Date, [start, end]: [Date, Date]): boolean {\n    return fieldValue >= start && fieldValue <= end;\n  }\n}\n\n// ✅ Generic operator registration with type safety\nOperatorRegistry.register<Date, [Date, Date]>(new DateRangeOperator());\n```\n\n## 📚 Documentation\n\n### Core Package\n- 📖 **[Core README](./packages/core/README.md)** - Complete API reference and examples\n- 🎯 **[Operators Guide](./packages/core/docs/operators.md)** - All 121+ operators with examples\n- 💡 **[Best Practices](./packages/core/docs/best-practices.md)** - Production patterns and tips\n- 🚀 **[Migration Guide](./packages/core/docs/migration-guide.md)** - Upgrading from other engines\n\n### Builder Package\n- 🏗️ **[Builder README](./packages/builder/README.md)** - React components and integration\n- 🎨 **[Component Reference](./packages/builder/docs/components.md)** - All UI components\n- ⌨️ **[Keyboard Shortcuts](./packages/builder/docs/shortcuts.md)** - Professional navigation\n- 🎯 **[Integration Examples](./packages/builder/docs/integration.md)** - Framework guides\n\n### Architecture & Development\n- 🏛️ **[Architecture Guide](./docs/architecture.md)** - System design and patterns\n- 🛠️ **[Development Setup](./docs/getting-started.md)** - Contributing and development\n- 📊 **[Comparison Guide](./docs/comparison.md)** - vs other rule engines\n\n## 🛠️ Development\n\n### Prerequisites\n- Node.js >= 18.12.0\n- pnpm >= 10.11.0\n\n### Setup\n```bash\n# Clone the repository\ngit clone https://github.com/ali-master/rule-engine.git\ncd rule-engine\n\n# Install dependencies\npnpm install\n\n# Build all packages\npnpm build\n\n# Run tests\npnpm test\n\n# Run linter\npnpm lint\n```\n\n### Package Scripts\n| Script | Description |\n|--------|-------------|\n| `pnpm build` | Build all packages |\n| `pnpm test` | Run all tests |\n| `pnpm lint` | Lint all packages |\n| `pnpm test:types` | Type checking |\n| `pnpm test:bench` | Performance benchmarks |\n\n## 🆚 Why Choose This Rule Engine?\n\n| Feature | @usex/rule-engine | json-rules-engine | node-rules |\n|---------|-------------------|-------------------|------------|\n| Zero Dependencies | ✅ | ❌ | ❌ |\n| **TypeScript Native** | **✅ 100% + Generics** | ⚠️ Partial | ❌ |\n| **Custom Operators** | **✅ Full Support** | ⚠️ Limited | ❌ |\n| JSONPath Support | ✅ | ❌ | ❌ |\n| Self-Referencing | ✅ | ❌ | ❌ |\n| Visual Builder | ✅ | ❌ | ❌ |\n| Generic Support | **✅ Input/Output** | ❌ | ❌ |\n| Performance (ops/sec) | 17k+ (55k+ JSONPath) | 45k | 30k |\n| Bundle Size | 12KB | 45KB | 38KB |\n| Browser Support | ✅ | ✅ | ❌ |\n| Rule Introspection | ✅ | ❌ | ❌ |\n| Fluent Builder | ✅ | ❌ | ❌ |\n\n## 🤝 Contributing\n\nWe love contributions! Whether it's:\n- 🐛 Bug reports and fixes\n- ✨ New operators or features\n- 📖 Documentation improvements\n- 🎨 Examples and tutorials\n- 🏗️ UI components for the builder\n\nSee our [Contributing Guide](./CONTRIBUTING.md) for details.\n\n### How to Contribute\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## 🗺️ Roadmap\n\n### Version 1.0 (Current)\n- ✅ Core rule engine with 121+ operators\n- ✅ **Full TypeScript support with generics**\n- ✅ **Custom operator registration system**\n- ✅ Visual rule builder for React\n- ✅ Comprehensive documentation\n- ✅ Performance optimizations\n\n### Version 1.1 (Q2 2025)\n- 🔄 **Enhanced TypeScript utilities** (type guards, validators)\n- 🔄 **Operator marketplace** with community operators\n- 🔄 Rule templates and marketplace\n- 🔄 GraphQL integration\n- 🔄 More operator types (geo, financial)\n- 🔄 Advanced debugging tools\n\n### Version 2.0 (Q4 2025)\n- 🔮 AI-powered rule suggestions\n- 🔮 Visual rule debugger\n- 🔮 Collaborative editing\n- 🔮 Mobile app support\n- 🔮 Multi-language operators\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](./LICENCE) file for details.\n\n## 🙏 Acknowledgments\n\n- Thanks to all contributors who have helped shape this project\n- Inspired by json-rules-engine and other rule engines\n- Built with modern web technologies and best practices\n\n## 💬 Support & Community\n\n- 📖 **[Documentation](./packages/core/docs)** - Complete guides and references\n- 🐛 **[Issue Tracker](https://github.com/ali-master/rule-engine/issues)** - Bug reports and feature requests\n- 💭 **[Discussions](https://github.com/ali-master/rule-engine/discussions)** - Community Q&A and ideas\n- 📧 **[Email](mailto:ali_4286@live.com)** - Direct contact\n\n## Star History\n\n<a href=\"https://www.star-history.com/#ali-master/rule-engine&Date&LogScale\">\n <picture>\n   <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://api.star-history.com/svg?repos=ali-master/rule-engine&type=Date&theme=dark\" />\n   <source media=\"(prefers-color-scheme: light)\" srcset=\"https://api.star-history.com/svg?repos=ali-master/rule-engine&type=Date\" />\n   <img alt=\"Star History Chart\" src=\"https://api.star-history.com/svg?repos=ali-master/rule-engine&type=Date\" />\n </picture>\n</a>\n\n---\n\n<div align=\"center\">\n\n**Built with ❤️ by [Ali Torki](https://github.com/ali-master) for the developer community**\n\n[⭐ Star us on GitHub](https://github.com/ali-master/rule-engine) • [📦 View on npm](https://www.npmjs.com/package/@usex/rule-engine) • [📖 Read the Docs](./packages/core/README.md)\n\n**Making complex business logic simple, one rule at a time.**\n\n</div>\n"
  },
  {
    "path": "assets/BRAND_ASSETS.md",
    "content": "# @usex/rule-engine Brand Assets\n\n> **Official brand assets and usage guidelines for the @usex/rule-engine project**\n\n## 📦 Available Assets\n\n### Package Logos\n\n#### @packages/core\n- **Purpose**: Rule evaluation and processing engine\n- **Design Concept**: IF-THEN-ELSE decision flow diagram\n- **Files**:\n  - `core-logo.svg` (vector, recommended)\n  - `core-logo.png` (raster, 200×200px)\n\n#### @packages/builder\n- **Purpose**: Visual rule construction interface\n- **Design Concept**: Drag & drop interface with component palette\n- **Files**:\n  - `builder-logo.svg` (vector, recommended)\n  - `builder-logo.png` (raster, 200×200px)\n\n### Social Media Preview\n- **Purpose**: Social sharing, GitHub repository preview\n- **Dimensions**: 1280×640px (optimized for social platforms)\n- **Files**:\n  - `social-preview.svg` (vector, recommended)\n  - `social-preview.png` (raster, 1280×640px)\n\n## 🎨 Design System\n\n### Color Palette\n\n#### Core Package Colors\n```css\n/* Primary Gradient: Electric Blue to Purple */\n--core-primary: linear-gradient(135deg, #3b82f6 0%, #6366f1 50%, #8b5cf6 100%);\n\n/* Success Path: Green */\n--core-success: linear-gradient(135deg, #10b981 0%, #059669 100%);\n\n/* Error Path: Orange to Red */\n--core-error: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%);\n```\n\n#### Builder Package Colors\n```css\n/* Primary Gradient: Orange to Pink */\n--builder-primary: linear-gradient(135deg, #f97316 0%, #ec4899 50%, #8b5cf6 100%);\n\n/* Creation Accent: Emerald to Cyan */\n--builder-accent: linear-gradient(135deg, #10b981 0%, #06b6d4 100%);\n\n/* Active Element: Golden */\n--builder-active: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);\n```\n\n### Typography\n- **Primary**: `system-ui, -apple-system, sans-serif`\n- **Monospace**: `monospace` (for code elements)\n- **Weights**: 400 (regular), 500 (medium), 600 (semibold), 700 (bold), 900 (black)\n\n### Visual Effects\n- **Glow**: `filter: drop-shadow(0 0 8px rgba(color, 0.4))`\n- **Shadow**: `filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.25))`\n- **Border Radius**: `8px` (small), `12px` (medium), `16px` (large)\n\n## 📐 Logo Specifications\n\n### Core Logo Elements\n- **Central Diamond**: IF decision node with white \"IF\" text\n- **Input Box**: Data input with `{data}` placeholder text\n- **Flow Paths**: TRUE (green) and FALSE (orange/red) branches\n- **Output Circles**: Success (✓) and error (✗) indicators\n- **Animated Flow**: Data processing visualization\n\n### Builder Logo Elements\n- **Canvas Area**: Workspace with dotted border\n- **Draggable Components**: AND, >, $.user.age blocks with trails\n- **Drop Zones**: Dashed outline target areas\n- **Component Palette**: Available building blocks\n- **Hand Cursor**: Interaction indicator with motion trail\n\n### Sizing Guidelines\n| Usage | Minimum Size | Recommended Size | Maximum Size |\n|-------|-------------|------------------|-------------|\n| Favicon | 16×16px | 32×32px | 64×64px |\n| Navigation | 24×24px | 32×32px | 48×48px |\n| Cards/Lists | 48×48px | 64×64px | 96×96px |\n| Headers | 96×96px | 120×120px | 200×200px |\n| Hero Sections | 120×120px | 200×200px | 400×400px |\n\n## ✅ Usage Guidelines\n\n### ✅ DO\n- Use the SVG versions for all digital applications\n- Maintain the original aspect ratio (1:1 square)\n- Ensure adequate clear space around logos (minimum 20% of logo width)\n- Use logos on contrasting backgrounds for optimal visibility\n- Respect the functional design concept when explaining the packages\n\n### ❌ DON'T\n- Stretch, skew, or distort the logos\n- Change the colors or gradients\n- Add additional elements or text to the logos\n- Use low-resolution PNG files when SVG is available\n- Place logos on busy backgrounds without sufficient contrast\n- Remove or modify the animated elements in digital contexts\n\n## 📱 Platform-Specific Usage\n\n### GitHub Repository\n- **README Header**: Use `core-logo.svg` at 120×120px\n- **Social Preview**: Use `social-preview.svg` (1280×640px)\n- **Issue Templates**: Small logo usage at 32×32px\n\n### NPM Package\n- **Package Icon**: Use `core-logo.png` (200×200px)\n- **Documentation**: Use `core-logo.svg` with flexible sizing\n\n### Social Media\n- **Twitter/X Cards**: Use `social-preview.svg`\n- **LinkedIn Posts**: Use `social-preview.svg`\n- **Avatar/Profile**: Use individual package logos at 400×400px\n\n### Documentation Sites\n- **Header Logo**: 120×120px recommended\n- **Navigation**: 32×32px recommended\n- **Footer**: 48×48px recommended\n\n## 🔗 Logo Meaning & Messaging\n\n### Core Package\n**Visual Message**: \"I process your data through decision logic\"\n- The diamond shape represents decision points (standard flowchart symbol)\n- The branching paths show TRUE/FALSE evaluation\n- The animated flow demonstrates active processing\n- Colors indicate different outcomes (green=success, red=error)\n\n### Builder Package\n**Visual Message**: \"I help you build rules visually\"\n- The canvas represents the workspace\n- Draggable blocks show the construction process\n- Drop zones indicate where components can be placed\n- The hand cursor shows user interaction\n\n## 📄 File Formats & Technical Specs\n\n### SVG Files (Recommended)\n- **Viewbox**: 200×200 (logos), 1280×640 (social preview)\n- **Optimization**: Minified and compressed\n- **Animations**: CSS animations for web compatibility\n- **Compatibility**: All modern browsers, design tools\n\n### PNG Files (Fallback)\n- **Resolution**: 200×200px (logos), 1280×640px (social preview)\n- **Format**: PNG-24 with transparency\n- **Compression**: Optimized for web delivery\n- **Background**: Transparent\n\n## 📞 Brand Contact\n\nFor questions about brand usage, asset requests, or licensing:\n\n- **Repository**: [github.com/ali-master/rule-engine](https://github.com/ali-master/rule-engine)\n- **Issues**: [Brand Asset Issues](https://github.com/ali-master/rule-engine/issues/new?labels=brand,assets)\n- **Maintainer**: [@ali-master](https://github.com/ali-master)\n\n---\n\n**Last Updated**: June 02, 2025\n**Version**: 2.1.0\n**License**: MIT License (same as project)\n\n**Made with ❤️ by [Ali Torki](https://github.com/ali-master)**\n"
  },
  {
    "path": "docs/architecture.md",
    "content": "# Architecture Overview\n\nThis document provides a comprehensive overview of the Rule Engine architecture, design decisions, and implementation details.\n\n## Table of Contents\n\n- [System Architecture](#system-architecture)\n- [Package Structure](#package-structure)\n- [Core Components](#core-components)\n- [Design Patterns](#design-patterns)\n- [Data Flow](#data-flow)\n- [Performance Architecture](#performance-architecture)\n- [Security Architecture](#security-architecture)\n\n## System Architecture\n\n### High-Level Architecture\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                        Application Layer                         │\n│  ┌─────────────────┐  ┌──────────────────┐  ┌───────────────┐ │\n│  │   React Apps    │  │   Node.js Apps   │  │  API Services │ │\n│  └────────┬────────┘  └────────┬─────────┘  └───────┬───────┘ │\n└───────────┼────────────────────┼─────────────────────┼─────────┘\n            │                    │                     │\n┌───────────┼────────────────────┼─────────────────────┼─────────┐\n│           │         Rule Engine SDK Layer            │         │\n│  ┌────────▼────────┐  ┌────────▼─────────┐  ┌──────▼───────┐ │\n│  │   UI Builder    │  │   Rule Engine    │  │  Validators  │ │\n│  │  (@usex/builder)│  │   (@usex/core)   │  │  & Utils     │ │\n│  └─────────────────┘  └──────────────────┘  └──────────────┘ │\n└────────────────────────────────────────────────────────────────┘\n```\n\n### Component Architecture\n\n```\nRule Engine Core\n├── Services\n│   ├── RuleEngine        # Main evaluation engine\n│   ├── Evaluator         # Rule evaluation logic\n│   ├── Validator         # Rule validation\n│   ├── Introspector      # Rule analysis\n│   ├── Builder           # Programmatic rule construction\n│   └── ObjectDiscovery   # JSONPath utilities\n│\n├── Operators\n│   ├── Comparison        # Basic comparisons\n│   ├── String            # String operations\n│   ├── Numeric           # Number operations\n│   ├── Array             # Array/collection operations\n│   ├── Date/Time         # Temporal operations\n│   ├── Type              # Type validation\n│   └── Custom            # User-defined operators\n│\n└── Types & Utils\n    ├── Rule Types        # Core type definitions\n    ├── JSONPath Utils    # Path resolution\n    ├── Date Utils        # Date handling\n    └── Error Utils       # Error management\n```\n\n## Package Structure\n\n### Monorepo Organization\n\n| Directory | Purpose | Key Contents |\n|-----------|---------|--------------|\n| `/packages/core` | Core rule engine | Engine, operators, types |\n| `/packages/builder` | React UI components | Visual builder, inputs |\n| `/apps/web` | Documentation site | Docs, examples, guides |\n| `/docs` | Project documentation | Architecture, guides |\n| `/scripts` | Build scripts | Automation, tooling |\n\n### Package Dependencies\n\n```mermaid\ngraph TD\n    A[@usex/rule-engine-builder] --> B[@usex/rule-engine]\n    C[React Apps] --> A\n    D[Node.js Apps] --> B\n    E[API Services] --> B\n```\n\n### Module Structure\n\n```typescript\n// Core Package Exports\nexport {\n  // Main Classes\n  RuleEngine,\n  ObjectDiscovery,\n  \n  // Types\n  RuleType,\n  Condition,\n  Constraint,\n  EvaluationResult,\n  \n  // Enums\n  OperatorsType,\n  ConditionType,\n  \n  // Utilities\n  validateRule,\n  introspectRule,\n  buildRule\n} from '@usex/rule-engine';\n\n// Builder Package Exports\nexport {\n  // Components\n  TreeRuleBuilder,\n  ModernRuleBuilder,\n  RuleEvaluator,\n  HistoryViewer,\n  \n  // Hooks\n  useEnhancedRuleStore,\n  useFieldDiscovery,\n  useKeyboardShortcuts,\n  \n  // Types\n  FieldConfig,\n  ThemeConfig\n} from '@usex/rule-engine-builder';\n```\n\n## Core Components\n\n### RuleEngine Service\n\nThe main service responsible for rule evaluation:\n\n```typescript\nclass RuleEngine {\n  // Singleton instance\n  private static instance: RuleEngine;\n  \n  // Mutation system for data preprocessing\n  private mutations: Map<string, MutationFunction>;\n  \n  // Cache for performance\n  private cache: Map<string, any>;\n  \n  // Core methods\n  async evaluate<T>(rule: RuleType<T>, criteria: any): Promise<EvaluationResult<T>>;\n  validate(rule: RuleType<any>): ValidationResult;\n  introspect(rule: RuleType<any>): IntrospectionResult;\n  \n  // Static API\n  static evaluate<T>(...args): Promise<EvaluationResult<T>>;\n  static validate(...args): ValidationResult;\n  static builder(): RuleBuilder;\n}\n```\n\n### Evaluator Pipeline\n\n```\nInput Data → Mutations → Validation → Evaluation → Result\n     ↓            ↓           ↓            ↓          ↓\n  Criteria   Transform   Type Check   Apply Rules  Output\n```\n\n### Operator System\n\n| Layer | Description | Example |\n|-------|-------------|---------|\n| **Registration** | Operator definition | `{ name: 'equals', evaluate: (a, b) => a === b }` |\n| **Categorization** | Logical grouping | Comparison, String, Numeric, etc. |\n| **Type Safety** | Input/output types | `<T>(field: T, value: T) => boolean` |\n| **Validation** | Pre-evaluation checks | Value type, range, format |\n| **Evaluation** | Actual comparison | Field value vs constraint value |\n\n## Design Patterns\n\n### 1. Strategy Pattern\n\nUsed for operator evaluation:\n\n```typescript\ninterface OperatorStrategy {\n  evaluate(fieldValue: any, constraintValue: any): boolean;\n}\n\nclass EqualsOperator implements OperatorStrategy {\n  evaluate(fieldValue: any, constraintValue: any): boolean {\n    return fieldValue === constraintValue;\n  }\n}\n\nclass OperatorFactory {\n  private strategies: Map<string, OperatorStrategy>;\n  \n  getOperator(type: string): OperatorStrategy {\n    return this.strategies.get(type);\n  }\n}\n```\n\n### 2. Builder Pattern\n\nFor programmatic rule construction:\n\n```typescript\nconst rule = RuleEngine.builder()\n  .add({\n    and: [\n      { field: 'age', operator: 'greater-than', value: 18 },\n      { field: 'country', operator: 'equals', value: 'US' }\n    ],\n    result: { allowed: true }\n  })\n  .default({ allowed: false })\n  .build();\n```\n\n### 3. Observer Pattern\n\nUsed in the UI for state management:\n\n```typescript\nclass RuleStore {\n  private listeners: Set<() => void> = new Set();\n  private state: RuleState;\n  \n  subscribe(listener: () => void) {\n    this.listeners.add(listener);\n    return () => this.listeners.delete(listener);\n  }\n  \n  notify() {\n    this.listeners.forEach(listener => listener());\n  }\n}\n```\n\n### 4. Command Pattern\n\nFor undo/redo functionality:\n\n```typescript\ninterface Command {\n  execute(): void;\n  undo(): void;\n}\n\nclass UpdateRuleCommand implements Command {\n  constructor(\n    private store: RuleStore,\n    private oldRule: Rule,\n    private newRule: Rule\n  ) {}\n  \n  execute() {\n    this.store.setRule(this.newRule);\n  }\n  \n  undo() {\n    this.store.setRule(this.oldRule);\n  }\n}\n```\n\n## Data Flow\n\n### Rule Evaluation Flow\n\n```\n1. Input Reception\n   └── Receive rule and criteria\n   \n2. Mutation Phase\n   ├── Apply registered mutations\n   └── Transform criteria data\n   \n3. Validation Phase\n   ├── Validate rule structure\n   ├── Check operator validity\n   └── Verify field paths\n   \n4. Resolution Phase\n   ├── Resolve JSONPath expressions\n   ├── Extract field values\n   └── Handle nested objects\n   \n5. Evaluation Phase\n   ├── Apply constraints\n   ├── Evaluate conditions\n   └── Aggregate results\n   \n6. Result Composition\n   └── Return evaluation result\n```\n\n### State Management Flow\n\n```\nUser Action → Component → Hook → Store → State Update → UI Update\n     ↓           ↓         ↓       ↓          ↓            ↓\n  Change      Handler   Action  Reducer    New State   Re-render\n```\n\n## Performance Architecture\n\n### Optimization Strategies\n\n| Strategy | Implementation | Impact |\n|----------|----------------|--------|\n| **Caching** | Memoize evaluation results | 40% faster for repeated rules |\n| **Lazy Evaluation** | Stop on first failure | 60% faster for failing rules |\n| **Path Optimization** | Pre-compile JSONPath | 30% faster path resolution |\n| **Batch Processing** | Evaluate multiple items | 50% throughput increase |\n| **Trust Mode** | Skip validation | 20% faster for trusted rules |\n\n### Memory Management\n\n```typescript\nclass CacheManager {\n  private cache: LRUCache<string, any>;\n  private maxSize: number = 1000;\n  \n  set(key: string, value: any) {\n    if (this.cache.size >= this.maxSize) {\n      const firstKey = this.cache.keys().next().value;\n      this.cache.delete(firstKey);\n    }\n    this.cache.set(key, value);\n  }\n}\n```\n\n### Concurrency Model\n\n```typescript\nclass BatchEvaluator {\n  async evaluateBatch<T>(\n    rule: RuleType<T>,\n    items: any[],\n    concurrency: number = 10\n  ): Promise<EvaluationResult<T>[]> {\n    const chunks = chunk(items, concurrency);\n    const results = [];\n    \n    for (const chunk of chunks) {\n      const chunkResults = await Promise.all(\n        chunk.map(item => this.evaluate(rule, item))\n      );\n      results.push(...chunkResults);\n    }\n    \n    return results;\n  }\n}\n```\n\n## Security Architecture\n\n### Input Validation\n\n| Layer | Protection | Implementation |\n|-------|------------|----------------|\n| **Schema Validation** | Rule structure | JSON Schema validation |\n| **Type Checking** | Data types | TypeScript + runtime checks |\n| **Path Validation** | JSONPath safety | Whitelist allowed paths |\n| **Operator Validation** | Valid operators | Operator registry check |\n| **Value Sanitization** | Input cleaning | XSS prevention, type coercion |\n\n### Security Patterns\n\n```typescript\nclass SecurityValidator {\n  // Prevent prototype pollution\n  validatePath(path: string): boolean {\n    const dangerous = ['__proto__', 'constructor', 'prototype'];\n    return !dangerous.some(d => path.includes(d));\n  }\n  \n  // Limit complexity\n  validateComplexity(rule: RuleType): boolean {\n    const depth = this.calculateDepth(rule);\n    const conditions = this.countConditions(rule);\n    \n    return depth <= MAX_DEPTH && conditions <= MAX_CONDITIONS;\n  }\n  \n  // Sanitize regex patterns\n  validateRegex(pattern: string): boolean {\n    try {\n      new RegExp(pattern);\n      return !pattern.includes('(?<') && // No lookbehind\n             !pattern.includes('{1000,}'); // No large repetitions\n    } catch {\n      return false;\n    }\n  }\n}\n```\n\n### Access Control Integration\n\n```typescript\ninterface RuleAccessControl {\n  canCreate: (user: User) => boolean;\n  canRead: (user: User, rule: Rule) => boolean;\n  canUpdate: (user: User, rule: Rule) => boolean;\n  canDelete: (user: User, rule: Rule) => boolean;\n  canEvaluate: (user: User, rule: Rule) => boolean;\n}\n\nclass RuleEngineWithACL extends RuleEngine {\n  constructor(private acl: RuleAccessControl) {\n    super();\n  }\n  \n  async evaluate(rule: RuleType, criteria: any, user: User) {\n    if (!this.acl.canEvaluate(user, rule)) {\n      throw new Error('Access denied');\n    }\n    return super.evaluate(rule, criteria);\n  }\n}\n```\n\n## Extension Architecture\n\n### Plugin System\n\n```typescript\ninterface RuleEnginePlugin {\n  name: string;\n  version: string;\n  \n  // Lifecycle hooks\n  onInit?(engine: RuleEngine): void;\n  beforeEvaluate?(rule: RuleType, criteria: any): void;\n  afterEvaluate?(result: EvaluationResult): void;\n  \n  // Extension points\n  operators?: Record<string, OperatorDefinition>;\n  mutations?: Record<string, MutationFunction>;\n  validators?: Record<string, ValidatorFunction>;\n}\n\nclass PluginManager {\n  private plugins: Map<string, RuleEnginePlugin> = new Map();\n  \n  register(plugin: RuleEnginePlugin) {\n    this.plugins.set(plugin.name, plugin);\n    plugin.onInit?.(this.engine);\n  }\n}\n```\n\n### Custom Operator Architecture\n\n```typescript\ninterface CustomOperator {\n  name: string;\n  category: string;\n  description: string;\n  \n  // Type constraints\n  acceptedFieldTypes: FieldType[];\n  acceptedValueTypes: ValueType[];\n  \n  // Validation\n  validate(value: any): ValidationResult;\n  \n  // Evaluation\n  evaluate(fieldValue: any, constraintValue: any): boolean;\n  \n  // UI hints\n  ui?: {\n    icon?: string;\n    color?: string;\n    inputComponent?: React.ComponentType;\n  };\n}\n```\n\n## Future Architecture Considerations\n\n### Scalability\n\n- **Distributed Evaluation**: Rule evaluation across multiple workers\n- **Rule Compilation**: Compile rules to optimized JavaScript\n- **Streaming Support**: Process data streams with rules\n- **Edge Computing**: Run rules at the edge for low latency\n\n### Extensibility\n\n- **Plugin Marketplace**: Community-contributed operators and plugins\n- **Rule Templates**: Reusable rule patterns\n- **AI Integration**: ML-powered rule suggestions\n- **Visual Debugging**: Step-through rule evaluation\n\n---\n\nFor more technical details, see the [API Reference](../packages/core/docs/api-reference.md)."
  },
  {
    "path": "docs/comparison.md",
    "content": "# Rule Engine Comparison\n\nThis document compares @usex/rule-engine with other popular rule engines to help you make an informed decision.\n\n## Table of Contents\n\n- [Feature Comparison](#feature-comparison)\n- [Performance Comparison](#performance-comparison)\n- [API Comparison](#api-comparison)\n- [Use Case Comparison](#use-case-comparison)\n- [Migration Guides](#migration-guides)\n\n## Feature Comparison\n\n### Overall Feature Matrix\n\n| Feature | @usex/rule-engine | json-rules-engine | node-rules | nools | drools |\n|---------|-------------------|-------------------|------------|-------|--------|\n| **Language** | TypeScript/JS     | JavaScript | JavaScript | JavaScript | Java |\n| **JSON-based DSL** | ✅ Yes             | ✅ Yes | ❌ Code-based | ⚠️ Partial | ⚠️ DRL |\n| **Visual Builder** | ✅ Built-in        | ❌ No | ❌ No | ❌ No | ⚠️ External |\n| **TypeScript Support** | ✅ Native          | ⚠️ @types | ❌ No | ❌ No | N/A |\n| **Browser Support** | ✅ Yes             | ✅ Yes | ✅ Yes | ❌ No | ❌ No |\n| **JSONPath** | ✅ Yes             | ❌ No | ❌ No | ❌ No | ❌ No |\n| **Operators Count** | 121+              | ~20 | ~15 | ~10 | 50+ |\n| **Async Support** | ✅ Yes             | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |\n| **History/Undo** | ✅ Built-in        | ❌ No | ❌ No | ❌ No | ❌ No |\n| **Real-time Testing** | ✅ Built-in        | ❌ No | ❌ No | ❌ No | ⚠️ External |\n| **Dependencies** | 0 (core)          | 0 | 2 | 3 | Many |\n| **Bundle Size** | 42KB              | 38KB | 45KB | 120KB | N/A |\n| **License** | MIT               | MIT | MIT | MIT | Apache 2.0 |\n\n### Detailed Feature Breakdown\n\n#### Rule Definition\n\n| Feature | @usex/rule-engine | json-rules-engine | node-rules |\n|---------|-------------------|-------------------|------------|\n| **JSON Rules** | ✅ Native JSON | ✅ Native JSON | ❌ JavaScript functions |\n| **Visual Builder** | ✅ React component | ❌ Manual JSON | ❌ Code only |\n| **Rule Validation** | ✅ Built-in | ⚠️ Basic | ❌ Runtime only |\n| **Type Safety** | ✅ Full generics | ⚠️ Basic types | ❌ No types |\n| **Self-referencing** | ✅ JSONPath refs | ❌ No | ❌ No |\n| **Nested Conditions** | ✅ Unlimited | ✅ Limited | ✅ Yes |\n\n#### Operators & Evaluation\n\n| Feature | @usex/rule-engine | json-rules-engine | node-rules |\n|---------|-------------------|-------------------|------------|\n| **Built-in Operators** | 121+              | ~20 | ~15 |\n| **Custom Operators** | ✅ Yes             | ✅ Yes | ✅ Yes |\n| **Date/Time Ops** | ✅ 14 operators    | ⚠️ Basic | ❌ Manual |\n| **Array Operations** | ✅ 12 operators    | ⚠️ Basic | ❌ Manual |\n| **String Operations** | ✅ 12 operators    | ⚠️ Basic | ⚠️ Basic |\n| **Type Validation** | ✅ 10 operators    | ❌ No | ❌ No |\n| **Regex Support** | ✅ Native          | ⚠️ Custom | ⚠️ Custom |\n\n#### Developer Experience\n\n| Feature | @usex/rule-engine | json-rules-engine | node-rules |\n|---------|-------------------|-------------------|------------|\n| **Documentation** | ✅ Comprehensive | ✅ Good | ⚠️ Basic |\n| **Examples** | ✅ 15+ examples | ✅ 5+ examples | ⚠️ Few |\n| **TypeScript** | ✅ Native | ⚠️ @types | ❌ No |\n| **IDE Support** | ✅ Full IntelliSense | ⚠️ Partial | ❌ Limited |\n| **Testing Utils** | ✅ Built-in | ❌ Manual | ❌ Manual |\n| **Debug Mode** | ✅ Yes | ✅ Yes | ⚠️ Basic |\n\n## Performance Comparison\n\n### Benchmark Results\n\nTest setup: 10,000 evaluations, average of 10 runs\n\n| Engine | Simple Rule (5 conditions) | Complex Rule (20 conditions) | Nested Rule (3 levels) |\n|--------|---------------------------|------------------------------|------------------------|\n| **@usex/rule-engine** | 85ms (~117K/sec) | 250ms (~40K/sec) | 180ms (~55K/sec) |\n| **json-rules-engine** | 92ms (~108K/sec) | 310ms (~32K/sec) | 220ms (~45K/sec) |\n| **node-rules** | 78ms (~128K/sec) | 280ms (~35K/sec) | 195ms (~51K/sec) |\n| **nools** | 125ms (~80K/sec) | 420ms (~23K/sec) | 350ms (~28K/sec) |\n\n### Memory Usage\n\n| Engine | Idle | 1K Rules | 10K Rules | 100K Rules |\n|--------|------|----------|-----------|------------|\n| **@usex/rule-engine** | 12MB | 25MB | 120MB | 980MB |\n| **json-rules-engine** | 10MB | 28MB | 150MB | 1.2GB |\n| **node-rules** | 15MB | 35MB | 180MB | 1.5GB |\n| **nools** | 25MB | 60MB | 350MB | 3GB |\n\n### Optimization Features\n\n| Feature | @usex/rule-engine | json-rules-engine | node-rules |\n|---------|-------------------|-------------------|------------|\n| **Lazy Evaluation** | ✅ Yes | ✅ Yes | ⚠️ Partial |\n| **Result Caching** | ✅ Built-in | ❌ Manual | ❌ Manual |\n| **Batch Processing** | ✅ Native | ❌ Manual | ❌ Manual |\n| **Trust Mode** | ✅ Skip validation | ❌ No | ❌ No |\n| **Parallel Eval** | ✅ Promise.all | ✅ Promise.all | ⚠️ Limited |\n\n## API Comparison\n\n### Rule Definition Syntax\n\n#### @usex/rule-engine\n```javascript\n{\n  conditions: {\n    and: [\n      { field: \"age\", operator: \"greater-than\", value: 18 },\n      { field: \"status\", operator: \"equals\", value: \"active\" }\n    ]\n  },\n  default: { value: false }\n}\n```\n\n#### json-rules-engine\n```javascript\n{\n  conditions: {\n    all: [{\n      fact: 'age',\n      operator: 'greaterThanInclusive',\n      value: 18\n    }, {\n      fact: 'status',\n      operator: 'equal',\n      value: 'active'\n    }]\n  },\n  event: {\n    type: 'allow-access',\n    params: { message: 'Access granted' }\n  }\n}\n```\n\n#### node-rules\n```javascript\n{\n  name: \"access-rule\",\n  condition: function(R) {\n    R.when(this.age >= 18 && this.status === 'active');\n  },\n  consequence: function(R) {\n    this.result = true;\n    R.stop();\n  }\n}\n```\n\n### Evaluation API\n\n| Method | @usex/rule-engine | json-rules-engine | node-rules |\n|--------|-------------------|-------------------|------------|\n| **Basic Eval** | `RuleEngine.evaluate(rule, data)` | `engine.run(facts)` | `R.execute(fact)` |\n| **Boolean Check** | `RuleEngine.checkIsPassed(rule, data)` | Manual check | Manual check |\n| **Result Only** | `RuleEngine.getEvaluateResult(rule, data)` | Manual extract | Manual extract |\n| **Batch Eval** | `RuleEngine.evaluate(rule, dataArray)` | Loop manually | Loop manually |\n| **Validation** | `RuleEngine.validate(rule)` | No built-in | No built-in |\n\n## Use Case Comparison\n\n### Best For\n\n| Use Case | Best Choice | Reason |\n|----------|-------------|--------|\n| **Complex Business Rules** | @usex/rule-engine | Most operators, visual builder |\n| **Simple Boolean Logic** | node-rules | Lightweight, fast |\n| **Event-driven Systems** | json-rules-engine | Event-based design |\n| **Enterprise Java** | drools | Java ecosystem |\n| **Visual Rule Building** | @usex/rule-engine | Built-in React components |\n| **Browser Applications** | @usex/rule-engine | Zero deps, small bundle |\n| **Microservices** | @usex/rule-engine or json-rules-engine | JSON portability |\n\n### Feature Requirements\n\n| Need | Recommended | Why                       |\n|------|-------------|---------------------------|\n| **Visual Builder UI** | @usex/rule-engine | Only one with built-in UI |\n| **JSONPath Support** | @usex/rule-engine | Native JSONPath support   |\n| **TypeScript** | @usex/rule-engine | Native TypeScript         |\n| **Many Operators** | @usex/rule-engine | 121+ built-in operators   |\n| **Simple Rules** | node-rules or json-rules-engine | Simpler API               |\n| **Java Integration** | drools | JVM-based                 |\n\n## Migration Guides\n\n### From json-rules-engine\n\nKey differences:\n- `fact` → `field`\n- `all/any` → `and/or`\n- `event` → `result` in conditions or `default`\n\n```javascript\n// json-rules-engine\n{\n  conditions: {\n    all: [{\n      fact: 'temperature',\n      operator: 'greaterThan',\n      value: 100\n    }]\n  },\n  event: { type: 'hot-alert' }\n}\n\n// @usex/rule-engine\n{\n  conditions: {\n    and: [{\n      field: 'temperature',\n      operator: 'greater-than',\n      value: 100\n    }],\n    result: { alert: 'hot-alert' }\n  }\n}\n```\n\n### From node-rules\n\nKey differences:\n- Function-based → JSON-based\n- `this` context → explicit field paths\n- Consequences → results\n\n```javascript\n// node-rules\n{\n  condition: function(R) {\n    R.when(this.price > 100 && this.category === 'electronics');\n  },\n  consequence: function(R) {\n    this.discount = 0.10;\n    R.stop();\n  }\n}\n\n// @usex/rule-engine\n{\n  conditions: {\n    and: [\n      { field: 'price', operator: 'greater-than', value: 100 },\n      { field: 'category', operator: 'equals', value: 'electronics' }\n    ],\n    result: { discount: 0.10 }\n  }\n}\n```\n\n### From nools\n\nKey differences:\n- Flow-based → Condition-based\n- Session management → Stateless evaluation\n- Facts → Direct data objects\n\n```javascript\n// nools\nflow.rule(\"Discount\", [\n  Customer, \"c\", \"c.type == 'premium'\",\n  Order, \"o\", \"o.total > 100\"\n], function(facts) {\n  facts.o.discount = 0.20;\n});\n\n// @usex/rule-engine\n{\n  conditions: {\n    and: [\n      { field: 'customer.type', operator: 'equals', value: 'premium' },\n      { field: 'order.total', operator: 'greater-than', value: 100 }\n    ],\n    result: { discount: 0.20 }\n  }\n}\n```\n\n## Decision Matrix\n\n### Quick Decision Guide\n\nChoose **@usex/rule-engine** if you need:\n- ✅ Visual rule builder UI\n- ✅ Comprehensive operator set (121+)\n- ✅ JSONPath support\n- ✅ TypeScript-first design\n- ✅ Browser compatibility\n- ✅ History/undo functionality\n\nChoose **json-rules-engine** if you need:\n- ✅ Event-driven architecture\n- ✅ Proven production stability\n- ✅ Simple fact-based rules\n- ❌ Don't need UI components\n\nChoose **node-rules** if you need:\n- ✅ Maximum performance\n- ✅ Simple boolean logic\n- ✅ Programmatic rule definition\n- ❌ Don't need complex operators\n\nChoose **drools** if you need:\n- ✅ Java/JVM environment\n- ✅ Enterprise features\n- ✅ BRMS capabilities\n- ❌ Not using JavaScript\n\n## Summary\n\n@usex/rule-engine offers the most comprehensive feature set for JavaScript/TypeScript applications, especially when visual rule building and extensive operator support are required. While other engines may excel in specific areas (performance, simplicity, or ecosystem), @usex/rule-engine provides the best overall developer experience and flexibility for modern web applications.\n\n---\n\nFor detailed migration instructions, see the [Migration Guide](../packages/core/docs/migration-guide.md).\n"
  },
  {
    "path": "docs/getting-started.md",
    "content": "# Getting Started Guide\n\nWelcome to the Rule Engine! This guide will help you get up and running quickly with both the core engine and the visual builder.\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Your First Rule](#your-first-rule)\n- [Understanding Rules](#understanding-rules)\n- [Using the Visual Builder](#using-the-visual-builder)\n- [Common Patterns](#common-patterns)\n- [Next Steps](#next-steps)\n\n## Installation\n\n### Core Engine Only\n\nIf you only need the rule evaluation engine:\n\n```bash\nnpm install @usex/rule-engine\n```\n\n### With Visual Builder\n\nFor the complete experience with UI components:\n\n```bash\nnpm install @usex/rule-engine @usex/rule-engine-builder\n```\n\n### Peer Dependencies\n\nThe builder requires React 18 or 19:\n\n```json\n{\n  \"peerDependencies\": {\n    \"react\": \"^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^18.0.0 || ^19.0.0\"\n  }\n}\n```\n\n## Your First Rule\n\n### Basic Example\n\nLet's create a simple rule to check if a user is eligible for a discount:\n\n```typescript\nimport { RuleEngine } from '@usex/rule-engine';\n\n// Define the rule\nconst discountRule = {\n  conditions: {\n    and: [\n      { field: \"age\", operator: \"greater-than\", value: 18 },\n      { field: \"membershipLevel\", operator: \"equals\", value: \"gold\" }\n    ]\n  },\n  default: { value: false }\n};\n\n// Test data\nconst customer = {\n  age: 25,\n  membershipLevel: \"gold\",\n  totalPurchases: 1500\n};\n\n// Evaluate the rule\nconst result = await RuleEngine.evaluate(discountRule, customer);\nconsole.log(result); \n// { value: true, isPassed: true }\n```\n\n### Understanding the Result\n\nThe evaluation returns an object with:\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `value` | `any` | The result value (from condition or default) |\n| `isPassed` | `boolean` | Whether any condition matched |\n| `message` | `string?` | Optional message from constraints |\n\n## Understanding Rules\n\n### Rule Structure\n\nEvery rule has two main parts:\n\n```typescript\ninterface Rule {\n  conditions: Condition | Condition[];  // What to evaluate\n  default?: any;                       // Fallback if no match\n}\n```\n\n### Conditions\n\nConditions group constraints using logical operators:\n\n```typescript\n// AND - All must match\n{\n  and: [\n    { field: \"age\", operator: \"greater-than\", value: 21 },\n    { field: \"country\", operator: \"equals\", value: \"US\" }\n  ]\n}\n\n// OR - Any must match\n{\n  or: [\n    { field: \"role\", operator: \"equals\", value: \"admin\" },\n    { field: \"role\", operator: \"equals\", value: \"moderator\" }\n  ]\n}\n\n// NONE - None must match\n{\n  none: [\n    { field: \"status\", operator: \"equals\", value: \"banned\" },\n    { field: \"status\", operator: \"equals\", value: \"suspended\" }\n  ]\n}\n```\n\n### Constraints\n\nThe basic building blocks:\n\n```typescript\ninterface Constraint {\n  field: string;      // What to check\n  operator: string;   // How to check\n  value?: any;        // What to compare against\n  message?: string;   // Optional validation message\n}\n```\n\n## Using the Visual Builder\n\n### Basic Setup\n\n```tsx\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\nimport '@usex/rule-engine-builder/styles';\n\nfunction App() {\n  const [rule, setRule] = useState(null);\n  \n  const handleRuleChange = (newRule) => {\n    setRule(newRule);\n    console.log('Rule updated:', newRule);\n  };\n  \n  return (\n    <div className=\"app\">\n      <TreeRuleBuilder\n        onChange={handleRuleChange}\n        showJsonViewer={true}\n        showToolbar={true}\n      />\n      \n      {rule && (\n        <div className=\"result\">\n          <h3>Generated Rule:</h3>\n          <pre>{JSON.stringify(rule, null, 2)}</pre>\n        </div>\n      )}\n    </div>\n  );\n}\n```\n\n### With Custom Fields\n\nDefine your business fields:\n\n```tsx\nconst fields = [\n  {\n    name: 'customer.tier',\n    label: 'Customer Tier',\n    type: 'string',\n    group: 'Customer',\n    values: [\n      { value: 'bronze', label: 'Bronze' },\n      { value: 'silver', label: 'Silver' },\n      { value: 'gold', label: 'Gold' }\n    ]\n  },\n  {\n    name: 'order.total',\n    label: 'Order Total',\n    type: 'number',\n    group: 'Order'\n  },\n  {\n    name: 'order.items.length',\n    label: 'Item Count',\n    type: 'number',\n    group: 'Order'\n  }\n];\n\n<TreeRuleBuilder\n  fields={fields}\n  onChange={handleRuleChange}\n/>\n```\n\n### With Sample Data\n\nProvide sample data for testing:\n\n```tsx\nconst sampleData = {\n  customer: {\n    tier: 'gold',\n    joinDate: '2023-01-15',\n    totalSpent: 2500\n  },\n  order: {\n    total: 150,\n    items: ['item1', 'item2', 'item3']\n  }\n};\n\n<TreeRuleBuilder\n  fields={fields}\n  sampleData={sampleData}\n  onChange={handleRuleChange}\n  showJsonViewer={true}\n/>\n```\n\n## Common Patterns\n\n### 1. Discount Rules\n\n```typescript\nconst discountRule = {\n  conditions: [\n    // VIP customers get 20% off\n    {\n      and: [\n        { field: \"customer.tier\", operator: \"equals\", value: \"vip\" },\n        { field: \"order.total\", operator: \"greater-than\", value: 100 }\n      ],\n      result: { discount: 0.20, message: \"VIP discount applied!\" }\n    },\n    // New customers get 10% off\n    {\n      and: [\n        { field: \"customer.isNew\", operator: \"equals\", value: true },\n        { field: \"order.total\", operator: \"greater-than\", value: 50 }\n      ],\n      result: { discount: 0.10, message: \"Welcome discount!\" }\n    }\n  ],\n  default: { discount: 0, message: \"No discount available\" }\n};\n```\n\n### 2. Access Control\n\n```typescript\nconst accessRule = {\n  conditions: {\n    or: [\n      // Admins have full access\n      { field: \"user.role\", operator: \"equals\", value: \"admin\" },\n      // Owners can access their own resources\n      {\n        and: [\n          { field: \"user.id\", operator: \"equals\", value: \"$.resource.ownerId\" },\n          { field: \"resource.public\", operator: \"equals\", value: false }\n        ]\n      },\n      // Anyone can access public resources\n      { field: \"resource.public\", operator: \"equals\", value: true }\n    ]\n  },\n  default: { value: false }\n};\n```\n\n### 3. Form Validation\n\n```typescript\nconst validationRule = {\n  conditions: {\n    and: [\n      // Email validation\n      { \n        field: \"email\", \n        operator: \"matches\", \n        value: \"^[^@]+@[^@]+\\\\.[^@]+$\",\n        message: \"Invalid email format\"\n      },\n      // Age restriction\n      { \n        field: \"age\", \n        operator: \"between\", \n        value: [18, 100],\n        message: \"Age must be between 18 and 100\"\n      },\n      // Password strength\n      { \n        field: \"password\", \n        operator: \"matches\", \n        value: \"^(?=.*[a-z])(?=.*[A-Z])(?=.*\\\\d).{8,}$\",\n        message: \"Password must contain uppercase, lowercase, and number\"\n      }\n    ]\n  }\n};\n```\n\n### 4. Dynamic Pricing\n\n```typescript\nconst pricingRule = {\n  conditions: [\n    // Bulk discount\n    {\n      and: [\n        { field: \"quantity\", operator: \"greater-than\", value: 100 }\n      ],\n      result: { multiplier: 0.8, reason: \"Bulk discount\" }\n    },\n    // Premium customer discount\n    {\n      and: [\n        { field: \"customer.tier\", operator: \"in\", value: [\"gold\", \"platinum\"] },\n        { field: \"quantity\", operator: \"greater-than\", value: 10 }\n      ],\n      result: { multiplier: 0.85, reason: \"Premium customer discount\" }\n    }\n  ],\n  default: { multiplier: 1, reason: \"Standard pricing\" }\n};\n```\n\n## Advanced Features\n\n### JSONPath Support\n\nAccess nested data with JSONPath:\n\n```typescript\nconst rule = {\n  conditions: {\n    and: [\n      // Access nested object\n      { field: \"$.user.profile.age\", operator: \"greater-than\", value: 18 },\n      \n      // Access array element\n      { field: \"$.orders[0].total\", operator: \"greater-than\", value: 100 },\n      \n      // Filter arrays\n      { field: \"$.items[?(@.price > 50)]\", operator: \"not-empty\", value: true }\n    ]\n  }\n};\n```\n\n### Self-referencing\n\nReference other fields in values:\n\n```typescript\nconst rule = {\n  conditions: {\n    and: [\n      // Compare two fields\n      { field: \"$.currentPrice\", operator: \"less-than\", value: \"$.maxPrice\" },\n      \n      // Percentage of another field\n      { field: \"$.discount\", operator: \"less-than-or-equals\", value: \"$.maxDiscount\" }\n    ]\n  }\n};\n```\n\n### Complex Nested Rules\n\n```typescript\nconst complexRule = {\n  conditions: {\n    or: [\n      // Premium path\n      {\n        and: [\n          { field: \"tier\", operator: \"equals\", value: \"premium\" },\n          {\n            or: [\n              { field: \"purchases\", operator: \"greater-than\", value: 10 },\n              { field: \"totalSpent\", operator: \"greater-than\", value: 1000 }\n            ]\n          }\n        ]\n      },\n      // VIP override\n      { field: \"isVIP\", operator: \"equals\", value: true }\n    ]\n  }\n};\n```\n\n## Testing Your Rules\n\n### Simple Test\n\n```typescript\n// Quick boolean check\nconst isPassed = await RuleEngine.checkIsPassed(rule, data);\nconsole.log('Rule passed:', isPassed); // true or false\n\n// Get just the result value\nconst value = await RuleEngine.getEvaluateResult(rule, data);\nconsole.log('Result:', value); // The actual result value\n```\n\n### Batch Testing\n\n```typescript\nconst testCases = [\n  { name: \"John\", age: 25, tier: \"gold\" },\n  { name: \"Jane\", age: 17, tier: \"silver\" },\n  { name: \"Bob\", age: 30, tier: \"bronze\" }\n];\n\nconst results = await RuleEngine.evaluate(rule, testCases);\nresults.forEach((result, index) => {\n  console.log(`${testCases[index].name}: ${result.isPassed}`);\n});\n```\n\n### Validation\n\nAlways validate rules before using them:\n\n```typescript\nconst validation = RuleEngine.validate(rule);\n\nif (!validation.isValid) {\n  console.error('Invalid rule:', validation.error.message);\n} else {\n  // Safe to use the rule\n  const result = await RuleEngine.evaluate(rule, data);\n}\n```\n\n## Next Steps\n\nNow that you understand the basics:\n\n1. **Explore Operators**: Check the [Operators Guide](../packages/core/docs/operators.md) for all 126+ operators\n2. **Learn Best Practices**: Read the [Best Practices Guide](../packages/core/docs/best-practices.md)\n3. **Try Examples**: See real-world [Examples](../packages/builder/docs/examples.md)\n4. **Build Complex Rules**: Use the [Visual Builder](../packages/builder/README.md)\n5. **Integrate**: Follow the [Integration Guide](../packages/builder/docs/integration.md)\n\n## Quick Reference\n\n### Common Operators\n\n| Operator | Description | Example |\n|----------|-------------|---------|\n| `equals` | Exact match | `{ operator: \"equals\", value: \"active\" }` |\n| `greater-than` | Greater than | `{ operator: \"greater-than\", value: 18 }` |\n| `contains` | Array/string contains | `{ operator: \"contains\", value: \"admin\" }` |\n| `between` | Range check | `{ operator: \"between\", value: [10, 20] }` |\n| `matches` | Regex match | `{ operator: \"matches\", value: \"^[A-Z]\" }` |\n| `exists` | Field exists | `{ operator: \"exists\", value: true }` |\n| `empty` | Is empty | `{ operator: \"empty\", value: true }` |\n\n### Keyboard Shortcuts (Builder)\n\n| Shortcut | Action |\n|----------|--------|\n| `Ctrl/Cmd + Z` | Undo |\n| `Ctrl/Cmd + Y` | Redo |\n| `Ctrl/Cmd + S` | Save |\n| `Ctrl/Cmd + E` | Toggle evaluation |\n| `?` | Show help |\n\n---\n\nReady to build more complex rules? Check out our [Examples](../packages/builder/docs/examples.md) or dive into the [API Reference](../packages/core/docs/api-reference.md)!"
  },
  {
    "path": "eslint.config.js",
    "content": "import antfu from \"@antfu/eslint-config\";\n\nexport default antfu({\n  formatters: {\n    prettierOptions: {\n      printWidth: 100,\n      trailingComma: \"all\",\n      singleQuote: false,\n      semi: true,\n      tabWidth: 2,\n      quoteProps: \"as-needed\",\n      jsxSingleQuote: false,\n      arrowParens: \"always\",\n    },\n  },\n  stylistic: false,\n  typescript: true,\n  name: \"rule-engine\",\n  react: true,\n  gitignore: true,\n  pnpm: false,\n  jsonc: false,\n}).append({\n  ignores: [\n    \"README.md\",\n    \"packages/*/README.md\",\n    \"packages/*/CHANGELOG.md\",\n    \"packages/*/dist\",\n    \"packages/*/dist-demo\",\n    \"packages/*/node_modules\",\n    \"packages/*/coverage\",\n    \"**/*.json\",\n  ],\n  files: [\"./packages/**/*.ts\", \"./packages/**/*.tsx\"],\n  rules: {\n    eqeqeq: \"off\",\n    \"prefer-regex-literals\": \"off\",\n    \"unicorn/number-literal-case\": \"off\",\n    \"regexp/no-dupe-characters-character-class\": \"off\",\n    \"no-misleading-character-class\": \"off\",\n    \"regexp/no-misleading-unicode-character\": \"off\",\n    \"regexp/no-obscure-range\": \"off\",\n    \"react-refresh/only-export-components\": \"off\",\n    \"no-labels\": \"off\",\n    \"no-cond-assign\": \"off\",\n    \"no-async-promise-executor\": \"off\",\n    \"no-new\": \"off\",\n    \"no-console\": \"off\",\n    \"antfu/top-level-function\": \"off\",\n    \"ts/no-unsafe-function-type\": \"off\",\n    \"perfectionist/sort-imports\": \"off\",\n    \"ts/explicit-function-return-type\": \"off\",\n    \"regexp/no-unused-capturing-group\": \"off\",\n    \"node/prefer-global/buffer\": \"off\",\n    \"node/prefer-global/process\": \"off\",\n    \"no-throw-literal\": \"off\",\n    \"ts/ban-ts-comment\": \"off\",\n    \"ts/method-signature-style\": \"off\",\n    \"ts/no-non-null-asserted-optional-chain\": \"off\",\n    \"react-hooks-extra/no-direct-set-state-in-use-effect\": \"off\",\n    \"react/no-array-index-key\": \"off\",\n    \"perfectionist/sort-named-imports\": [\"error\", { order: \"desc\" }],\n  },\n});\n"
  },
  {
    "path": "knip.json",
    "content": "{\n  \"$schema\": \"https://unpkg.com/knip@5/schema.json\",\n  \"project\": [\"./packages/*/src/**/*.ts\"]\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"rule-engine-monorepo\",\n  \"preview\": true,\n  \"type\": \"module\",\n  \"packageManager\": \"pnpm@10.17.1\",\n  \"description\": \"A monorepo of Rule Engine implementation for NodeJS and Browser. It includes a core rule engine and various plugins.\",\n  \"author\": {\n    \"name\": \"Ali Torki\",\n    \"email\": \"ali_4286@live.com\",\n    \"url\": \"https://github.com/ali-master\"\n  },\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"build\": \"pnpm -r build\",\n    \"build:demo\": \"pnpm -r build:demo\",\n    \"lint\": \"pnpm -r lint\",\n    \"lint:fix\": \"pnpm -r lint:fix\",\n    \"format:check\": \"pnpm -r format:check\",\n    \"format\": \"pnpm -r format\",\n    \"test:junit\": \"pnpm -r test:junit\",\n    \"test:unit\": \"pnpm -r test:unit\",\n    \"test:types\": \"pnpm -r test:types\",\n    \"test:knip\": \"pnpm -r test:knip\",\n    \"test:coverage\": \"pnpm -r test:coverage\",\n    \"release\": \"pnpm -r release\",\n    \"release:beta\": \"pnpm -r release:beta\",\n    \"postinstall\": \"simple-git-hooks install\"\n  },\n  \"devDependencies\": {\n    \"@antfu/eslint-config\": \"5.4.1\",\n    \"@eslint-react/eslint-plugin\": \"^1.53.1\",\n    \"@types/node\": \"24.5.2\",\n    \"@typescript/native-preview\": \"7.0.0-dev.20250922.1\",\n    \"@vitest/coverage-v8\": \"^3.2.4\",\n    \"@vitest/ui\": \"^3.2.4\",\n    \"changelogithub\": \"13.16.0\",\n    \"cross-env\": \"^10.0.0\",\n    \"eslint\": \"9.36.0\",\n    \"eslint-plugin-format\": \"^1.0.2\",\n    \"eslint-plugin-react-hooks\": \"^5.2.0\",\n    \"eslint-plugin-react-refresh\": \"^0.4.21\",\n    \"installed-check\": \"9.3.0\",\n    \"knip\": \"5.64.0\",\n    \"lint-staged\": \"16.2.0\",\n    \"prettier\": \"^3.6.2\",\n    \"simple-git-hooks\": \"2.13.1\",\n    \"standard-version\": \"^9.5.0\",\n    \"unbuild\": \"^3.6.1\",\n    \"vitest\": \"3.2.4\"\n  },\n  \"resolutions\": {\n    \"@usex/builder\": \"workspace:*\",\n    \"@usex/rule-engine\": \"workspace:*\"\n  },\n  \"simple-git-hooks\": {\n    \"pre-commit\": \"pnpm lint-staged\"\n  },\n  \"lint-staged\": {\n    \"*.{js,ts,mjs,cjs,json,.*rc}\": [\n      \"pnpm lint:fix\"\n    ]\n  }\n}\n"
  },
  {
    "path": "packages/builder/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-demo\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n"
  },
  {
    "path": "packages/builder/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n\n### 0.0.3 (2025-06-10)\n\n\n### Features\n\n* **AdvancedFieldInput:** refactor code for improved readability and maintainability ([8e3e1ff](https://github.com/ali-master/rule-engine/commit/8e3e1ff74c3c1dc60128850eb87b57c1cb2ade23))\n* **App, TreeRuleBuilder, UndoRedoInfo:** integrate enhanced rule store with undo/redo functionality and keyboard shortcuts ([e85e89b](https://github.com/ali-master/rule-engine/commit/e85e89bebe0fec64d04f370dcf6342aadcd74067))\n* **App:** implement rule evaluation feature with UI enhancements ([be42689](https://github.com/ali-master/rule-engine/commit/be42689773b385ac4bb8504920e53483e9977766))\n* **builder:** add shadcn ([216c8a7](https://github.com/ali-master/rule-engine/commit/216c8a7ac425e64e3344b9aa441f35bfd64df6d2))\n* **Builder:** added the smart builder ui ([eeb9468](https://github.com/ali-master/rule-engine/commit/eeb94685a16863288d6f51d4b4a136e03a41790e))\n* **Calendar, DateInput, TreeConstraintEditor:** enhance calendar functionality and add animations ([94404e4](https://github.com/ali-master/rule-engine/commit/94404e49bd607e791721dcc6ba30d7a85d849efb))\n* **DateInput, TreeConstraintEditor:** enhance date parsing and add visual field selector ([b9dd735](https://github.com/ali-master/rule-engine/commit/b9dd735a038703c559a9d1f32ba7f0ddbf71a522))\n* **Dialog:** refactor dialog components for improved readability and structure ([c530113](https://github.com/ali-master/rule-engine/commit/c530113d58b01f9f3c1ebf916652dff10580d70f))\n* **DiffViewer:** add DiffStats component for enhanced property change visualization ([f8f74c5](https://github.com/ali-master/rule-engine/commit/f8f74c57f486c6b426dceae17cbeb059991b9594))\n* **EditableJsonViewer:** add keyboard shortcuts for live evaluation and enhance tooltip information ([6cfb41f](https://github.com/ali-master/rule-engine/commit/6cfb41f268b751e50c998ae47741d12585f11d40))\n* **EditableJsonViewer:** add live evaluation feature and improve diff visualization ([fc4caee](https://github.com/ali-master/rule-engine/commit/fc4caeeba4d8d63657bf637d5bac1828670e8042))\n* **HistoryViewer:** implement history viewer with search, filter, and version comparison features ([77c52c0](https://github.com/ali-master/rule-engine/commit/77c52c0d51aa7628a4e1180f19125c87dbe47e8a))\n* **HistoryViewer:** integrate ResizablePanel for improved layout flexibility ([bc7b918](https://github.com/ali-master/rule-engine/commit/bc7b9185f9c3db1a4a91a16201a634b37f3d0de0))\n* **HistoryViewer:** replace select element with custom Select component for action filtering ([ffc7b07](https://github.com/ali-master/rule-engine/commit/ffc7b0799e72816e5da692d47e8393cd668075c6))\n* **JsonViewer:** add highlight for logical operators and improve scrollbar handling ([9f159bc](https://github.com/ali-master/rule-engine/commit/9f159bc9f6a33d2f479e27be225c48961074d826))\n* **JsonViewer:** integrate JsonViewer component for improved JSON display and editing experience ([8ead760](https://github.com/ali-master/rule-engine/commit/8ead7605c7257c1a493d6273af682dc632041e8c))\n* **OperatorSelector:** add search functionality and improve operator grouping ([10dd6c4](https://github.com/ali-master/rule-engine/commit/10dd6c484d176c0ed49ac0d7c69b36d8ce82e05f))\n* **TreeConditionGroup:** enhance condition type styling with improved colors and animations ([aa5bb4a](https://github.com/ali-master/rule-engine/commit/aa5bb4ae10afcb9e78f006f5cd974d5858fc8d57))\n* **TreeConstraintEditor:** add advanced field selector mode and integrate SmartOperatorSelector ([03d40ec](https://github.com/ali-master/rule-engine/commit/03d40ec93341580f3e375c0f4450c39cdc75c5a4))\n* **TreeConstraintEditor:** enhance operator selection with tooltips and improved layout ([cd7a728](https://github.com/ali-master/rule-engine/commit/cd7a728326da6f26077146f3ce1df2cbbb178f4a))\n* **TreeRuleBuilder, VisualFieldSelector:** enhance UI with regex helper and improved tab functionality ([cacef1a](https://github.com/ali-master/rule-engine/commit/cacef1a27bf932753df20319cd43b7a4f1da19b4))\n* **VisualFieldSelector:** enhance value preview layout and improve JsonViewer integration ([59d962a](https://github.com/ali-master/rule-engine/commit/59d962ae12b3127a666eab8b105feadc45cfa77c))\n* **VisualFieldSelector:** integrate JsonViewer for enhanced JSON value preview ([52bb37c](https://github.com/ali-master/rule-engine/commit/52bb37c1112e6d857d28cb430c58692c6c579d3a))\n\n\n### Bug Fixes\n\n* **HistoryViewer:** layout and overflow ([7f357a4](https://github.com/ali-master/rule-engine/commit/7f357a49bf7b9904e6bc964ff40ed85779d52eec))\n\n### [0.0.1](https://github.com/ali-master/rule-engine/compare/v0.0.2...v0.0.1) (2025-06-10)\n"
  },
  {
    "path": "packages/builder/README.md",
    "content": "<div align=\"center\">\n  <img src=\"../../assets/builder-logo.svg\" alt=\"Rule Engine Builder Logo\" width=\"120\" />\n\n  <h1>@usex/rule-engine-builder</h1>\n  <p><strong>🎨 Visual Rule Constructor for React Applications</strong></p>\n\n  <p>\n    <a href=\"https://www.npmjs.com/package/@usex/rule-engine-builder\"><img src=\"https://img.shields.io/npm/v/@usex/rule-engine-builder?style=flat-square\" alt=\"npm version\" /></a>\n    <a href=\"https://github.com/ali-master/rule-engine/blob/master/LICENSE\"><img src=\"https://img.shields.io/npm/l/@usex/rule-engine-builder?style=flat-square\" alt=\"license\" /></a>\n    <a href=\"https://codecov.io/gh/ali-master/rule-engine\"><img src=\"https://codecov.io/gh/ali-master/rule-engine/graph/badge.svg?token=UN5opqxNsi\" alt=\"codecov\" /></a>\n    <a href=\"https://www.npmjs.com/package/@usex/rule-engine-builder\"><img src=\"https://img.shields.io/npm/dm/@usex/rule-engine-builder?style=flat-square\" alt=\"downloads\" /></a>\n    <a href=\"https://github.com/ali-master/rule-engine\"><img src=\"https://img.shields.io/github/stars/ali-master/rule-engine?style=flat-square\" alt=\"stars\" /></a>\n  </p>\n\n  <p>\n    <a href=\"#-quick-start\">Quick Start</a> •\n    <a href=\"./docs/components.md\">Components</a> •\n    <a href=\"./docs/examples.md\">Examples</a> •\n    <a href=\"#-why-visual-builder\">Why Visual Builder?</a>\n  </p>\n</div>\n\n---\n\nCreate complex business rules with an intuitive drag-and-drop interface. No more JSON wrestling - build rules visually and export to your rule engine.\n\n```typescript\n// Instead of writing complex JSON...\nconst rule = {\n  conditions: [\n    {\n      and: [\n        { field: \"$.user.tier\", operator: \"equals\", value: \"premium\" },\n        { field: \"$.order.total\", operator: \"greater-than\", value: 100 }\n      ],\n      result: { discount: 0.15, shipping: \"free\" }\n    }\n  ]\n};\n\n// Just drag, drop, and configure visually! 🎨\n<RuleBuilder \n  onRuleChange={setRule}\n  availableFields={fields}\n  theme=\"dark\"\n/>\n```\n\n## 🚀 Why Visual Builder?\n\n**Intuitive Visual Interface**\n- 🎨 **Drag & Drop** - Build rules by dragging components onto a canvas\n- 🌲 **Tree Structure** - Visual representation of complex nested logic\n- 📦 **Component Palette** - Pre-built operators, fields, and logic blocks\n- 🎯 **Drop Zones** - Smart targeting for precise rule construction\n\n**Developer-Friendly Experience**\n- ⚡ **Real-time Preview** - See JSON output as you build\n- 🔄 **Live Evaluation** - Test rules instantly with sample data\n- 📈 **History Management** - Undo/redo with 100-entry history\n- ⌨️ **Keyboard Shortcuts** - Professional keyboard navigation\n\n**Production-Ready Features**\n- 🛡️ **TypeScript Native** - Full type safety and IntelliSense support\n- 🎨 **Theme System** - Light/dark modes with full customization\n- ♿ **Accessible** - WCAG compliant with screen reader support\n- 📱 **Responsive** - Works on desktop, tablet, and mobile devices\n\n**Extensible & Customizable**\n- 🔧 **Custom Operators** - Add your own business-specific operators\n- 🎛️ **Field Discovery** - Auto-suggest fields from your data schema\n- 🌈 **Custom Themes** - Match your application's design system\n- 📊 **Export Options** - JSON, TypeScript, or custom formats\n\n## 🎬 Quick Start\n\n```bash\nnpm install @usex/rule-engine-builder @usex/rule-engine react\n```\n\n### Basic Usage\n\n```tsx\nimport React, { useState } from 'react';\nimport { RuleBuilder } from '@usex/rule-engine-builder';\nimport { RuleEngine } from '@usex/rule-engine';\n\nfunction App() {\n  const [rule, setRule] = useState(null);\n  \n  // Define available fields for your users\n  const availableFields = [\n    { name: '$.user.tier', type: 'string', label: 'User Tier' },\n    { name: '$.user.age', type: 'number', label: 'User Age' },\n    { name: '$.order.total', type: 'number', label: 'Order Total' },\n    { name: '$.order.items', type: 'array', label: 'Order Items' }\n  ];\n\n  // Test data for live evaluation\n  const testData = {\n    user: { tier: 'premium', age: 28 },\n    order: { total: 150, items: ['laptop', 'mouse'] }\n  };\n\n  return (\n    <div className=\"app\">\n      <h1>Build Your Business Rules</h1>\n      \n      <RuleBuilder\n        rule={rule}\n        onRuleChange={setRule}\n        availableFields={availableFields}\n        testData={testData}\n        theme=\"auto\"\n        showPreview={true}\n        showHistory={true}\n      />\n      \n      {rule && (\n        <div className=\"rule-output\">\n          <h3>Generated Rule:</h3>\n          <pre>{JSON.stringify(rule, null, 2)}</pre>\n          \n          <button onClick={() => testRule()}>\n            Test Rule\n          </button>\n        </div>\n      )}\n    </div>\n  );\n\n  async function testRule() {\n    if (!rule) return;\n    \n    const result = await RuleEngine.evaluate(rule, testData);\n    console.log('Rule Result:', result);\n  }\n}\n```\n\n## 🏗️ Core Components\n\n### RuleBuilder (Main Component)\n\nThe primary visual rule construction interface.\n\n```tsx\n<RuleBuilder\n  rule={rule}                    // Current rule state\n  onRuleChange={setRule}         // Callback when rule changes\n  availableFields={fields}       // Available fields for selection\n  testData={testData}           // Sample data for live testing\n  theme=\"dark\"                  // Theme: 'light' | 'dark' | 'auto'\n  showPreview={true}            // Show JSON preview panel\n  showHistory={true}            // Enable undo/redo functionality\n  customOperators={operators}    // Custom business operators\n  onValidationError={onError}   // Validation error callback\n  className=\"my-rule-builder\"   // Custom CSS classes\n/>\n```\n\n### RuleEvaluator\n\nReal-time rule evaluation with visual feedback.\n\n```tsx\n<RuleEvaluator\n  rule={rule}\n  testData={testData}\n  engine={RuleEngine}\n  onResult={handleResult}\n  showSteps={true}              // Show evaluation steps\n  highlightActive={true}        // Highlight active rule paths\n/>\n```\n\n### ModernConstraintEditor\n\nAdvanced constraint editing with intelligent suggestions.\n\n```tsx\n<ModernConstraintEditor\n  constraint={constraint}\n  onConstraintChange={setConstraint}\n  availableFields={fields}\n  operators={operators}\n  showFieldSuggestions={true}\n  allowCustomFields={true}\n/>\n```\n\n## 🔧 Component Showcase\n\n### Building Blocks\n\nThe visual builder provides intuitive components for every rule element:\n\n#### Logic Operators\n- **AND** - All conditions must be true\n- **OR** - Any condition must be true  \n- **NONE** - No conditions must be true\n\n#### Comparison Operators\n- **Equals (=)** - Exact value matching\n- **Greater Than (>)** - Numeric comparison\n- **Contains** - Array/string inclusion\n- **Matches** - Regular expression patterns\n\n#### Field Selectors\n- **JSONPath Fields** - `$.user.profile.name`\n- **Nested Properties** - Deep object navigation\n- **Array Elements** - `$.items[0].price`\n- **Custom Fields** - User-defined properties\n\n#### Value Inputs\n- **Static Values** - Fixed strings, numbers, booleans\n- **Dynamic References** - `$.other.field`\n- **Arrays** - Multiple value selection\n- **Date/Time** - Calendar and time pickers\n\n## 🎯 Real-World Examples\n\n### E-commerce Discount Builder\n\n```tsx\nfunction DiscountRuleBuilder() {\n  const [discountRule, setDiscountRule] = useState(null);\n  \n  const ecommerceFields = [\n    { name: '$.customer.tier', type: 'string', label: 'Customer Tier', \n      options: ['bronze', 'silver', 'gold', 'platinum'] },\n    { name: '$.cart.total', type: 'number', label: 'Cart Total' },\n    { name: '$.cart.itemCount', type: 'number', label: 'Number of Items' },\n    { name: '$.customer.isFirstOrder', type: 'boolean', label: 'First Order' },\n    { name: '$.promotions.active', type: 'array', label: 'Active Promotions' }\n  ];\n\n  const customOperators = [\n    {\n      name: 'is-weekend',\n      label: 'Is Weekend',\n      category: 'datetime',\n      description: 'Check if current date is weekend'\n    },\n    {\n      name: 'bulk-discount-eligible',\n      label: 'Bulk Discount Eligible',\n      category: 'business',\n      description: 'Check if order qualifies for bulk pricing'\n    }\n  ];\n\n  return (\n    <div className=\"discount-builder\">\n      <h2>Discount Rule Builder</h2>\n      \n      <RuleBuilder\n        rule={discountRule}\n        onRuleChange={setDiscountRule}\n        availableFields={ecommerceFields}\n        customOperators={customOperators}\n        theme=\"light\"\n        resultTemplate={{\n          discount: 0,\n          code: '',\n          message: '',\n          expires: null\n        }}\n      />\n    </div>\n  );\n}\n```\n\n### User Access Control Builder\n\n```tsx\nfunction AccessControlBuilder() {\n  const [accessRule, setAccessRule] = useState(null);\n  \n  const accessFields = [\n    { name: '$.user.role', type: 'string', label: 'User Role' },\n    { name: '$.user.department', type: 'string', label: 'Department' },\n    { name: '$.user.clearanceLevel', type: 'number', label: 'Clearance Level' },\n    { name: '$.resource.sensitivity', type: 'string', label: 'Resource Sensitivity' },\n    { name: '$.session.duration', type: 'number', label: 'Session Duration' },\n    { name: '$.time.currentHour', type: 'number', label: 'Current Hour' }\n  ];\n\n  return (\n    <div className=\"access-builder\">\n      <h2>Access Control Rules</h2>\n      \n      <RuleBuilder\n        rule={accessRule}\n        onRuleChange={setAccessRule}\n        availableFields={accessFields}\n        theme=\"dark\"\n        showHistory={true}\n        resultTemplate={{\n          allowed: false,\n          permissions: [],\n          expires: null,\n          reason: ''\n        }}\n      />\n      \n      <RuleEvaluator\n        rule={accessRule}\n        testData={sampleUserSession}\n        showSteps={true}\n        onResult={(result) => {\n          console.log('Access Decision:', result);\n        }}\n      />\n    </div>\n  );\n}\n```\n\n### Form Validation Builder\n\n```tsx\nfunction ValidationBuilder() {\n  const [validationRules, setValidationRules] = useState([]);\n  \n  const formFields = [\n    { name: 'email', type: 'string', label: 'Email Address' },\n    { name: 'password', type: 'string', label: 'Password' },\n    { name: 'confirmPassword', type: 'string', label: 'Confirm Password' },\n    { name: 'age', type: 'number', label: 'Age' },\n    { name: 'country', type: 'string', label: 'Country' },\n    { name: 'acceptTerms', type: 'boolean', label: 'Accept Terms' }\n  ];\n\n  return (\n    <div className=\"validation-builder\">\n      <h2>Form Validation Rules</h2>\n      \n      {validationRules.map((rule, index) => (\n        <div key={index} className=\"validation-rule\">\n          <h3>Rule {index + 1}</h3>\n          \n          <RuleBuilder\n            rule={rule}\n            onRuleChange={(newRule) => {\n              const updated = [...validationRules];\n              updated[index] = newRule;\n              setValidationRules(updated);\n            }}\n            availableFields={formFields}\n            mode=\"validation\"\n            showPreview={false}\n          />\n        </div>\n      ))}\n      \n      <button onClick={() => addValidationRule()}>\n        Add Validation Rule\n      </button>\n    </div>\n  );\n}\n```\n\n## 🎨 Advanced Features\n\n### Custom Themes\n\n```tsx\nconst customTheme = {\n  colors: {\n    primary: '#6366f1',\n    secondary: '#10b981',\n    background: '#f8fafc',\n    surface: '#ffffff',\n    text: '#1f2937',\n    border: '#e5e7eb'\n  },\n  spacing: {\n    sm: '0.5rem',\n    md: '1rem',\n    lg: '1.5rem'\n  },\n  borderRadius: '0.75rem',\n  shadows: {\n    sm: '0 1px 2px rgba(0, 0, 0, 0.05)',\n    md: '0 4px 6px rgba(0, 0, 0, 0.1)'\n  }\n};\n\n<RuleBuilder\n  rule={rule}\n  onRuleChange={setRule}\n  theme={customTheme}\n  availableFields={fields}\n/>\n```\n\n### Field Discovery\n\n```tsx\n// Auto-discover fields from your data schema\nconst fields = useFieldDiscovery(sampleData, {\n  maxDepth: 3,\n  includeArrays: true,\n  typeInference: true\n});\n\n<RuleBuilder\n  rule={rule}\n  onRuleChange={setRule}\n  availableFields={fields}\n  allowFieldDiscovery={true}\n  onFieldDiscovered={(field) => {\n    console.log('New field discovered:', field);\n  }}\n/>\n```\n\n### History Management\n\n```tsx\nfunction RuleBuilderWithHistory() {\n  const [rule, setRule] = useState(null);\n  const { history, undo, redo, canUndo, canRedo } = useRuleHistory();\n\n  return (\n    <div>\n      <div className=\"history-controls\">\n        <button \n          onClick={undo} \n          disabled={!canUndo}\n          title=\"Undo (Ctrl+Z)\"\n        >\n          ↶ Undo\n        </button>\n        \n        <button \n          onClick={redo} \n          disabled={!canRedo}\n          title=\"Redo (Ctrl+Y)\"\n        >\n          ↷ Redo\n        </button>\n        \n        <span className=\"history-count\">\n          Step {history.currentIndex + 1} of {history.entries.length}\n        </span>\n      </div>\n\n      <RuleBuilder\n        rule={rule}\n        onRuleChange={setRule}\n        showHistory={true}\n        maxHistoryEntries={100}\n      />\n    </div>\n  );\n}\n```\n\n### Keyboard Shortcuts\n\nThe builder supports professional keyboard navigation:\n\n| Shortcut | Action |\n|----------|--------|\n| `Ctrl+Z` | Undo last change |\n| `Ctrl+Y` | Redo last undone change |\n| `Ctrl+D` | Duplicate selected component |\n| `Delete` | Remove selected component |\n| `Tab` | Navigate between components |\n| `Enter` | Edit selected component |\n| `Escape` | Cancel current operation |\n| `Ctrl+S` | Export rule (custom handler) |\n\n## 🏎️ Performance & Optimization\n\n### Virtual Scrolling\n\nFor large rule sets, the builder uses virtual scrolling:\n\n```tsx\n<RuleBuilder\n  rule={complexRule}\n  onRuleChange={setRule}\n  virtualScrolling={true}\n  itemHeight={60}\n  maxVisibleItems={50}\n/>\n```\n\n### Lazy Loading\n\nComponents are loaded on-demand for better performance:\n\n```tsx\nconst LazyRuleBuilder = lazy(() => import('@usex/rule-engine-builder'));\n\nfunction App() {\n  return (\n    <Suspense fallback={<div>Loading rule builder...</div>}>\n      <LazyRuleBuilder />\n    </Suspense>\n  );\n}\n```\n\n### Optimized Rendering\n\n```tsx\n// Use memo for expensive field calculations\nconst availableFields = useMemo(() => \n  generateFieldsFromSchema(schema), [schema]\n);\n\n// Debounce rule changes to reduce re-renders\nconst debouncedOnChange = useMemo(\n  () => debounce(setRule, 300),\n  []\n);\n\n<RuleBuilder\n  rule={rule}\n  onRuleChange={debouncedOnChange}\n  availableFields={availableFields}\n  optimizeRendering={true}\n/>\n```\n\n## 🎓 TypeScript Support\n\nFull type safety for all components and props:\n\n```tsx\ninterface CustomField {\n  name: string;\n  type: 'string' | 'number' | 'boolean' | 'array' | 'object';\n  label: string;\n  description?: string;\n  options?: string[];\n  validation?: {\n    required?: boolean;\n    min?: number;\n    max?: number;\n    pattern?: string;\n  };\n}\n\ninterface CustomRule<T = any> {\n  id: string;\n  conditions: Condition<T>[];\n  result?: T;\n  metadata?: {\n    name: string;\n    description: string;\n    created: Date;\n    modified: Date;\n  };\n}\n\n// Type-safe rule builder\nconst Builder = () => {\n  const [rule, setRule] = useState<CustomRule<DiscountResult>>(null);\n  \n  return (\n    <RuleBuilder<DiscountResult>\n      rule={rule}\n      onRuleChange={setRule}\n      availableFields={typedFields}\n      resultType=\"discount\"\n    />\n  );\n};\n```\n\n## 🧪 Testing Components\n\n```tsx\nimport { render, screen, fireEvent } from '@testing-library/react';\nimport { RuleBuilder } from '@usex/rule-engine-builder';\n\ndescribe('RuleBuilder', () => {\n  const mockFields = [\n    { name: 'age', type: 'number', label: 'Age' },\n    { name: 'country', type: 'string', label: 'Country' }\n  ];\n\n  it('should render field palette', () => {\n    render(\n      <RuleBuilder\n        availableFields={mockFields}\n        onRuleChange={jest.fn()}\n      />\n    );\n    \n    expect(screen.getByText('Age')).toBeInTheDocument();\n    expect(screen.getByText('Country')).toBeInTheDocument();\n  });\n\n  it('should handle drag and drop', () => {\n    const onChange = jest.fn();\n    \n    render(\n      <RuleBuilder\n        availableFields={mockFields}\n        onRuleChange={onChange}\n      />\n    );\n    \n    const ageField = screen.getByText('Age');\n    const dropZone = screen.getByTestId('drop-zone');\n    \n    fireEvent.dragStart(ageField);\n    fireEvent.drop(dropZone);\n    \n    expect(onChange).toHaveBeenCalledWith(\n      expect.objectContaining({\n        conditions: expect.arrayContaining([\n          expect.objectContaining({\n            field: 'age'\n          })\n        ])\n      })\n    );\n  });\n});\n```\n\n## 📚 Documentation & Resources\n\n- 🏗️ **[Component Guide](./docs/components.md)** - Detailed component documentation\n- 🎨 **[Theming Guide](./docs/theming.md)** - Customization and styling\n- ⌨️ **[Keyboard Shortcuts](./docs/shortcuts.md)** - Complete keyboard reference\n- 🔧 **[Integration Examples](./docs/integration.md)** - Framework-specific examples\n- 🎯 **[Best Practices](./docs/best-practices.md)** - Performance and UX guidelines\n- 📋 **[Changelog](./CHANGELOG.md)** - Version history and updates\n\n## 🤝 Contributing\n\nWe welcome contributions! Whether it's:\n- 🐛 Bug reports and fixes\n- ✨ New components or features\n- 📖 Documentation improvements\n- 🎨 Theme contributions\n\nSee our [Contributing Guide](../../CONTRIBUTING.md) for details.\n\n### Development Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/ali-master/rule-engine.git\ncd rule-engine/packages/builder\n\n# Install dependencies\npnpm install\n\n# Start development server\npnpm dev\n\n# Run tests\npnpm test\n\n# Build for production\npnpm build\n```\n\n## 🆚 Why Choose This Builder?\n\n| Feature | @usex/rule-engine-builder | React QueryBuilder | React Awesome Query Builder |\n|---------|---------------------------|--------------------|-----------------------------|\n| TypeScript Native | ✅ | ⚠️ Partial | ⚠️ Partial |\n| Drag & Drop | ✅ | ❌ | ✅ |\n| Real-time Evaluation | ✅ | ❌ | ❌ |\n| History/Undo | ✅ | ❌ | ❌ |\n| Custom Themes | ✅ | ⚠️ Limited | ✅ |\n| Mobile Responsive | ✅ | ⚠️ Partial | ❌ |\n| JSONPath Support | ✅ | ❌ | ❌ |\n| Bundle Size | 45KB | 120KB | 180KB |\n| Tree Visualization | ✅ | ❌ | ✅ |\n| Keyboard Shortcuts | ✅ | ❌ | ❌ |\n\n## 📄 License\n\nMIT © [Ali Torki](https://github.com/ali-master)\n\n---\n\n<div align=\"center\">\n\n**Built with ❤️ for modern React applications**\n\n[⭐ Star us on GitHub](https://github.com/ali-master/rule-engine) • [🐛 Report Issues](https://github.com/ali-master/rule-engine/issues) • [💬 Discussions](https://github.com/ali-master/rule-engine/discussions)\n\n</div>"
  },
  {
    "path": "packages/builder/components.json",
    "content": "{\n  \"$schema\": \"https://ui.shadcn.com/schema.json\",\n  \"style\": \"new-york\",\n  \"rsc\": false,\n  \"tsx\": true,\n  \"tailwind\": {\n    \"config\": \"\",\n    \"css\": \"src/main.css\",\n    \"baseColor\": \"neutral\",\n    \"cssVariables\": true,\n    \"prefix\": \"\"\n  },\n  \"aliases\": {\n    \"components\": \"@/components\",\n    \"utils\": \"@/lib/utils\",\n    \"ui\": \"@/components/ui\",\n    \"lib\": \"@/lib\",\n    \"hooks\": \"@/hooks\"\n  },\n  \"iconLibrary\": \"lucide\"\n}\n"
  },
  {
    "path": "packages/builder/docs/README.md",
    "content": "# @usex/rule-engine-builder Documentation\n\nWelcome to the comprehensive documentation for @usex/rule-engine-builder - a complete React component library for building visual rule engine interfaces.\n\n## 📚 Documentation Overview\n\n### Getting Started\n- [**README**](../README.md) - Installation, quick start, and overview\n- [**Integration Guide**](./integration.md) - Framework and backend integration\n- [**Examples**](./examples.md) - Real-world use cases and implementations\n\n### Component Documentation\n- [**Component Reference**](./components.md) - Complete component API documentation\n- [**Hooks Reference**](./hooks.md) - State management and utility hooks\n- [**UI Components**](./components.md#ui-components) - Available UI component library\n\n### Advanced Guides\n- [**Custom Operators**](../README.md#custom-operators) - Creating custom business logic\n- [**Theme Customization**](../README.md#theme-customization) - Styling and branding\n- [**Performance Optimization**](./integration.md#performance-optimization) - Best practices\n\n## 🚀 Quick Navigation\n\n| Topic | Documentation |\n|-------|---------------|\n| **Installation** | [README](../README.md#installation) |\n| **Basic Usage** | [README](../README.md#quick-start) |\n| **TreeRuleBuilder** | [Components](./components.md#treerulebuilder) |\n| **State Management** | [Hooks](./hooks.md#state-management-hooks) |\n| **Field Discovery** | [Hooks](./hooks.md#usefielddiscovery) |\n| **Keyboard Shortcuts** | [Hooks](./hooks.md#usekeyboardshortcuts) |\n| **React Integration** | [Integration](./integration.md#react-integration) |\n| **Next.js Setup** | [Integration](./integration.md#nextjs-integration) |\n| **E-commerce Examples** | [Examples](./examples.md#e-commerce-examples) |\n| **Access Control** | [Examples](./examples.md#access-control-examples) |\n| **Form Validation** | [Examples](./examples.md#form-validation-examples) |\n\n## 🎯 Component Categories\n\n### Primary Components\n\n| Component | Purpose | Documentation |\n|-----------|---------|---------------|\n| `TreeRuleBuilder` | Main rule builder interface | [Components](./components.md#treerulebuilder) |\n| `ModernRuleBuilder` | Enhanced with animations | [Components](./components.md#modernrulebuilder) |\n| `RuleEvaluator` | Real-time rule testing | [Components](./components.md#ruleevaluator) |\n| `HistoryViewer` | Version control | [Components](./components.md#historyviewer) |\n\n### Editor Components\n\n| Component | Purpose | Use Case |\n|-----------|---------|----------|\n| `TreeConditionGroup` | Nested logic groups | AND/OR/NONE conditions |\n| `TreeConstraintEditor` | Individual constraints | Field-operator-value editing |\n| `FieldSelector` | Field selection | Grouped field picker |\n| `OperatorSelector` | Operator selection | Categorized operators |\n\n### Input Components\n\n| Component | Type | Features |\n|-----------|------|----------|\n| `SmartValueInput` | Universal | Type-aware, validation |\n| `ArrayInput` | Array | Drag-and-drop reordering |\n| `DateInput` | Date/Time | Calendar, time zones |\n| `NumberInput` | Number | Animated, formatting |\n\n## 🔧 Integration Patterns\n\n### Framework Support\n\n| Framework | Status | Documentation |\n|-----------|--------|---------------|\n| **React** | ✅ Full Support | [Integration Guide](./integration.md#react-integration) |\n| **Next.js** | ✅ App & Pages Router | [Integration Guide](./integration.md#nextjs-integration) |\n| **Vite** | ✅ Optimized | [Integration Guide](./integration.md#vite-integration) |\n| **Create React App** | ✅ Supported | [README](../README.md#quick-start) |\n\n### State Management\n\n| Library | Status | Documentation |\n|---------|--------|---------------|\n| **Zustand** | ✅ Built-in | [Hooks](./hooks.md#useenhancedrulestore) |\n| **Redux Toolkit** | ✅ Supported | [Integration](./integration.md#redux-toolkit-integration) |\n| **TanStack Query** | ✅ Supported | [Integration](./integration.md#tanstack-query-integration) |\n| **Context API** | ✅ Supported | [Integration](./integration.md#with-context-providers) |\n\n### Backend Integration\n\n| Backend | Status | Documentation |\n|---------|--------|---------------|\n| **REST APIs** | ✅ Full Support | [Integration](./integration.md#expressjs-api) |\n| **GraphQL** | ✅ Full Support | [Integration](./integration.md#graphql-integration) |\n| **tRPC** | ✅ Compatible | [Integration](./integration.md#backend-integration) |\n| **Firebase** | ✅ Compatible | [Examples](./examples.md#integration-examples) |\n\n## 📖 Use Case Documentation\n\n### Business Applications\n\n| Use Case | Example | Documentation |\n|----------|---------|---------------|\n| **E-commerce** | Dynamic pricing, shipping | [Examples](./examples.md#e-commerce-examples) |\n| **Access Control** | RBAC, permissions | [Examples](./examples.md#access-control-examples) |\n| **Form Validation** | Registration, surveys | [Examples](./examples.md#form-validation-examples) |\n| **Business Logic** | Lead scoring, workflows | [Examples](./examples.md#business-logic-examples) |\n\n### Technical Implementations\n\n| Pattern | Description | Documentation |\n|---------|-------------|---------------|\n| **Multi-tenant SaaS** | Tenant-specific rules | [Examples](./examples.md#multi-tenant-saas-platform) |\n| **Real-time Evaluation** | Live rule testing | [Components](./components.md#ruleevaluator) |\n| **Version Control** | Rule history management | [Components](./components.md#historyviewer) |\n| **Custom Operators** | Domain-specific logic | [README](../README.md#custom-operators) |\n\n## 🎨 Customization Guide\n\n### Theming\n\n| Aspect | Customization | Documentation |\n|--------|---------------|---------------|\n| **Colors** | CSS variables, props | [README](../README.md#theme-customization) |\n| **Typography** | Font families, sizes | [Integration](./integration.md#styling-integration) |\n| **Layout** | Spacing, borders | [Integration](./integration.md#tailwind-css-integration) |\n| **Components** | Custom UI components | [Components](./components.md#ui-components) |\n\n### Behavior\n\n| Feature | Customization | Documentation |\n|---------|---------------|---------------|\n| **Keyboard Shortcuts** | Custom key bindings | [Hooks](./hooks.md#usekeyboardshortcuts) |\n| **Field Discovery** | Custom algorithms | [Hooks](./hooks.md#usefielddiscovery) |\n| **Validation** | Custom rules | [README](../README.md#form-validation-rules) |\n| **Operators** | Business logic | [README](../README.md#custom-operators) |\n\n## 🧪 Testing Documentation\n\n### Testing Strategies\n\n| Type | Tools | Documentation |\n|------|-------|---------------|\n| **Unit Tests** | Jest, Testing Library | [Integration](./integration.md#jest-testing) |\n| **Integration Tests** | MSW, Mock APIs | [Integration](./integration.md#testing-with-mock-service-worker) |\n| **E2E Tests** | Playwright, Cypress | [Integration](./integration.md#e2e-testing-with-playwright) |\n| **Visual Tests** | Storybook, Chromatic | [Integration](./integration.md#testing-integration) |\n\n## 📊 Performance Guide\n\n### Optimization Techniques\n\n| Technique | Implementation | Documentation |\n|-----------|----------------|---------------|\n| **Code Splitting** | Dynamic imports | [Integration](./integration.md#code-splitting) |\n| **Memoization** | React.memo, useMemo | [Integration](./integration.md#memoization) |\n| **Virtual Scrolling** | Large datasets | [Integration](./integration.md#virtual-scrolling) |\n| **Bundle Analysis** | Webpack analyzer | [Integration](./integration.md#bundle-analysis) |\n\n## 🔍 Troubleshooting\n\n### Common Issues\n\n| Issue | Solution | Documentation |\n|-------|----------|---------------|\n| **Styling conflicts** | CSS isolation | [Integration](./integration.md#styling-integration) |\n| **SSR hydration** | Dynamic imports | [Integration](./integration.md#nextjs-integration) |\n| **Performance** | Optimization patterns | [Integration](./integration.md#performance-optimization) |\n| **Type errors** | TypeScript setup | [README](../README.md#typescript-support) |\n\n## 🚀 Getting Started Checklist\n\n### Setup Steps\n\n- [ ] Install packages: `@usex/rule-engine-builder` and `@usex/rule-engine`\n- [ ] Import styles: `import '@usex/rule-engine-builder/styles'`\n- [ ] Add basic component: `<TreeRuleBuilder />`\n- [ ] Configure fields and sample data\n- [ ] Set up onChange handler\n- [ ] Add keyboard shortcuts (optional)\n- [ ] Customize theme (optional)\n- [ ] Set up backend integration (optional)\n\n### Quick Links\n\n- 📦 [Installation Guide](../README.md#installation)\n- 🚀 [Quick Start Tutorial](../README.md#quick-start)\n- 🎯 [Live Examples](./examples.md)\n- 🔧 [Integration Patterns](./integration.md)\n- 📚 [API Reference](./components.md)\n\n## 🤝 Contributing\n\nWant to improve the documentation?\n\n1. Check existing [issues](https://github.com/ali-master/rule-engine/issues)\n2. Read the [Contributing Guide](../../../CONTRIBUTING.md)\n3. Submit documentation improvements\n4. Help others in discussions\n\n## 📞 Support\n\n- **GitHub Issues**: [Report bugs or request features](https://github.com/ali-master/rule-engine/issues)\n- **Discussions**: [Community Q&A](https://github.com/ali-master/rule-engine/discussions)\n- **Documentation**: You're reading it! 📖\n\n---\n\n<div align=\"center\">\n  <p>\n    <strong>Made with ❤️ by the @usex/rule-engine community</strong>\n  </p>\n  <p>\n    <a href=\"https://github.com/ali-master/rule-engine\">GitHub</a> •\n    <a href=\"https://www.npmjs.com/package/@usex/rule-engine-builder\">npm</a> •\n    <a href=\"../README.md\">Documentation</a>\n  </p>\n</div>"
  },
  {
    "path": "packages/builder/docs/RuleEvaluator.md",
    "content": "# RuleEvaluator Component\n\nThe `RuleEvaluator` component provides a comprehensive interface for testing and evaluating rules in real-time against sample data. It features both live evaluation mode and manual evaluation, with detailed result visualization.\n\n## Features\n\n### Core Features\n- **Live Rule Evaluation**: Automatically evaluates rules as they change\n- **Manual Evaluation**: Evaluate rules on-demand with a single click\n- **Pass/Fail Indicators**: Clear visual feedback with red/green indicators\n- **Silent Mode**: Minimal UI showing just the pass/fail status\n- **Detailed Mode**: Comprehensive view showing which conditions passed or failed\n- **Smooth Animations**: Beautiful transitions powered by Framer Motion\n\n### Keyboard Shortcuts\n- `Ctrl/Cmd + E`: Toggle live evaluation mode\n- `Ctrl/Cmd + Shift + E`: Run evaluation once\n\n### UI Components\n- **Result Tab**: Shows overall evaluation result with pass/fail status\n- **Details Tab**: Hierarchical view of condition evaluation with drill-down capability\n- **Test Data Tab**: Editable JSON viewer for modifying test data on the fly\n\n## Usage\n\n```tsx\nimport { RuleEvaluator } from '@usex/rule-engine-builder';\n\nfunction MyApp() {\n  const handleEvaluationChange = (result) => {\n    console.log('Evaluation result:', result);\n  };\n\n  return (\n    <RuleEvaluator\n      defaultSampleData={mySampleData}\n      onEvaluationChange={handleEvaluationChange}\n      className=\"my-custom-class\"\n    />\n  );\n}\n```\n\n## Props\n\n| Prop | Type | Description | Default |\n|------|------|-------------|---------|\n| `className` | `string` | Additional CSS classes for styling | - |\n| `defaultSampleData` | `any` | Initial sample data for evaluation | `sampleEcommerceData` |\n| `onEvaluationChange` | `(result: EvaluationResult \\| null) => void` | Callback when evaluation result changes | - |\n\n## How It Works\n\n### Evaluation Process\n1. The component uses the `@usex/rule-engine` package to evaluate rules\n2. It subscribes to the enhanced rule store for rule updates\n3. In live mode, it automatically re-evaluates when rules change\n4. Results are displayed with detailed condition breakdowns\n\n### Visual Feedback\n- **Green indicators**: Rule or condition passed\n- **Red indicators**: Rule or condition failed\n- **Animated transitions**: Smooth UI updates for better UX\n- **Hierarchical display**: Nested conditions are indented and collapsible\n\n### Test Data Management\n- Edit test data directly in the component\n- Reset to default data with one click\n- JSON syntax validation\n- Real-time updates when data changes\n\n## Integration with Rule Builder\n\nThe `RuleEvaluator` component is designed to work seamlessly with the `TreeRuleBuilder`:\n\n```tsx\n<div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n  <div className=\"lg:col-span-2\">\n    <TreeRuleBuilder sampleData={sampleData} />\n  </div>\n  <div className=\"lg:col-span-1\">\n    <RuleEvaluator defaultSampleData={sampleData} />\n  </div>\n</div>\n```\n\n## Advanced Features\n\n### Condition Details\nThe component evaluates each condition recursively and shows:\n- Condition type (AND, OR, NONE)\n- Number of sub-conditions\n- Individual constraint evaluation results\n- Actual vs. expected values\n- Custom error messages\n\n### Performance\n- Debounced evaluation in live mode\n- Efficient re-rendering with React hooks\n- Minimal state updates\n- Optimized for large rule trees\n\n## Styling\n\nThe component uses Tailwind CSS and follows the design system of the rule builder. It supports:\n- Light and dark themes\n- Responsive design\n- Custom color schemes via CSS variables\n- Smooth animations and transitions\n\n## Error Handling\n\nThe component gracefully handles:\n- Invalid rule structures\n- Malformed test data\n- Evaluation errors\n- Network timeouts (if using async evaluation)\n\nErrors are displayed with clear messages and don't crash the UI."
  },
  {
    "path": "packages/builder/docs/components.md",
    "content": "# Component Reference\n\nComprehensive reference for all components in @usex/rule-engine-builder.\n\n## Table of Contents\n\n- [Primary Components](#primary-components)\n- [Editor Components](#editor-components)\n- [Input Components](#input-components)\n- [Utility Components](#utility-components)\n- [Hook Components](#hook-components)\n- [UI Components](#ui-components)\n\n## Primary Components\n\n### TreeRuleBuilder\n\nMain rule builder component with tree-based interface.\n\n```typescript\ninterface TreeRuleBuilderProps {\n  fields?: FieldConfig[];\n  sampleData?: Record<string, any>;\n  onChange?: (rule: any) => void;\n  onSave?: (rule: any) => void | Promise<void>;\n  onExport?: (rule: any, format: \"json\" | \"yaml\") => void;\n  onImport?: (data: string, format: \"json\" | \"yaml\") => void;\n  readOnly?: boolean;\n  className?: string;\n  showJsonViewer?: boolean;\n  showToolbar?: boolean;\n  maxNestingDepth?: number;\n  customOperators?: Record<string, any>;\n  theme?: \"light\" | \"dark\" | \"system\";\n  labels?: LabelConfig;\n  colors?: ColorConfig;\n  keyboardShortcuts?: KeyboardShortcuts;\n}\n```\n\n**Features:**\n- Tree-based rule construction\n- Drag-and-drop reordering\n- Keyboard shortcuts\n- History management\n- Real-time evaluation\n- Import/export functionality\n\n**Example:**\n```tsx\n<TreeRuleBuilder\n  fields={fields}\n  sampleData={data}\n  onChange={handleRuleChange}\n  onSave={handleSave}\n  showJsonViewer={true}\n  maxNestingDepth={5}\n/>\n```\n\n### ModernRuleBuilder\n\nEnhanced rule builder with modern UI and animations.\n\n```typescript\ninterface ModernRuleBuilderProps extends TreeRuleBuilderProps {\n  animations?: boolean;\n  dragAndDrop?: boolean;\n  virtualScrolling?: boolean;\n}\n```\n\n**Features:**\n- Framer Motion animations\n- Enhanced drag-and-drop\n- Virtual scrolling for large datasets\n- Modern design patterns\n\n### RuleEvaluator\n\nReal-time rule evaluation component.\n\n```typescript\ninterface RuleEvaluatorProps {\n  rule?: RuleType;\n  data?: Record<string, any>;\n  onDataChange?: (data: Record<string, any>) => void;\n  showKeyboardShortcuts?: boolean;\n  className?: string;\n}\n```\n\n**Features:**\n- Live rule evaluation\n- Sample data editing\n- Pass/fail indicators\n- Performance metrics\n- Keyboard shortcuts (Ctrl+E, Ctrl+Shift+E)\n\n**Example:**\n```tsx\n<RuleEvaluator\n  rule={currentRule}\n  data={testData}\n  onDataChange={setTestData}\n  showKeyboardShortcuts={true}\n/>\n```\n\n### HistoryViewer\n\nRule change history with version comparison.\n\n```typescript\ninterface HistoryViewerProps {\n  className?: string;\n}\n```\n\n**Features:**\n- 100-entry history\n- Version comparison\n- Diff visualization\n- Checkout previous versions\n- Search and filter\n\n**Example:**\n```tsx\n<HistoryViewer className=\"mt-4\" />\n```\n\n## Editor Components\n\n### TreeConditionGroup\n\nNested condition group management.\n\n```typescript\ninterface TreeConditionGroupProps {\n  condition: Condition;\n  path: number[];\n  depth: number;\n  fields: FieldConfig[];\n  sampleData?: Record<string, any>;\n  customOperators?: Record<string, any>;\n  maxNestingDepth?: number;\n  onUpdate: (condition: Condition) => void;\n  onRemove: () => void;\n  onDuplicate: () => void;\n  readOnly?: boolean;\n  labels?: LabelConfig;\n  colors?: ColorConfig;\n}\n```\n\n**Features:**\n- AND/OR/NONE logic groups\n- Nested conditions\n- Drag-and-drop reordering\n- Visual depth indicators\n- Expand/collapse state\n\n### TreeConstraintEditor\n\nIndividual constraint editing interface.\n\n```typescript\ninterface TreeConstraintEditorProps {\n  constraint: Constraint;\n  path: number[];\n  fields: FieldConfig[];\n  sampleData?: Record<string, any>;\n  customOperators?: Record<string, any>;\n  onUpdate: (constraint: Constraint) => void;\n  onRemove: () => void;\n  onDuplicate: () => void;\n  readOnly?: boolean;\n}\n```\n\n**Features:**\n- Field selection with groups\n- Operator categorization\n- Smart value inputs\n- Validation messages\n- Copy/paste support\n\n### FieldSelector\n\nAdvanced field selection interface.\n\n```typescript\ninterface FieldSelectorProps {\n  fields: FieldConfig[];\n  value?: string;\n  onChange: (field: string) => void;\n  placeholder?: string;\n  className?: string;\n  showGroups?: boolean;\n  allowCustom?: boolean;\n  jsonPathSupport?: boolean;\n}\n```\n\n**Features:**\n- Grouped field display\n- Search and filtering\n- JSONPath support\n- Custom field creation\n- Type indicators\n\n**Example:**\n```tsx\n<FieldSelector\n  fields={fields}\n  value={selectedField}\n  onChange={setSelectedField}\n  showGroups={true}\n  allowCustom={true}\n  jsonPathSupport={true}\n/>\n```\n\n### OperatorSelector\n\nCategorized operator selection.\n\n```typescript\ninterface OperatorSelectorProps {\n  operators: OperatorConfig[];\n  value?: string;\n  onChange: (operator: string) => void;\n  fieldType?: string;\n  className?: string;\n  showCategories?: boolean;\n  searchable?: boolean;\n}\n```\n\n**Features:**\n- Category-based grouping\n- Search functionality\n- Field type filtering\n- Help text and examples\n- Icon indicators\n\n## Input Components\n\n### SmartValueInput\n\nUniversal value input with type awareness.\n\n```typescript\ninterface SmartValueInputProps {\n  value: any;\n  onChange: (value: any) => void;\n  operator: string;\n  fieldType?: string;\n  field?: FieldConfig;\n  placeholder?: string;\n  className?: string;\n  validation?: ValidationConfig;\n}\n```\n\n**Features:**\n- Type-aware rendering\n- Operator-specific inputs\n- Validation feedback\n- Suggestions and autocomplete\n- Multi-value support\n\n**Example:**\n```tsx\n<SmartValueInput\n  value={constraintValue}\n  onChange={setValue}\n  operator=\"contains-any\"\n  fieldType=\"array\"\n  field={selectedField}\n/>\n```\n\n### ArrayInput\n\nArray value management with drag-and-drop.\n\n```typescript\ninterface ArrayInputProps {\n  value: any[];\n  onChange: (value: any[]) => void;\n  itemType?: string;\n  placeholder?: string;\n  maxItems?: number;\n  allowDuplicates?: boolean;\n  sortable?: boolean;\n  className?: string;\n}\n```\n\n**Features:**\n- Add/remove items\n- Drag-and-drop reordering\n- Type-specific item inputs\n- Duplicate detection\n- Validation per item\n\n### DateInput\n\nAdvanced date/time picker.\n\n```typescript\ninterface DateInputProps {\n  value: Date | string;\n  onChange: (value: Date | string) => void;\n  format?: string;\n  showTime?: boolean;\n  timeZone?: string;\n  minDate?: Date;\n  maxDate?: Date;\n  className?: string;\n}\n```\n\n**Features:**\n- Calendar popup\n- Time selection\n- Time zone support\n- Format customization\n- Range validation\n\n### NumberInput\n\nAnimated number input with validation.\n\n```typescript\ninterface NumberInputProps {\n  value: number;\n  onChange: (value: number) => void;\n  min?: number;\n  max?: number;\n  step?: number;\n  precision?: number;\n  animated?: boolean;\n  format?: Intl.NumberFormatOptions;\n  className?: string;\n}\n```\n\n**Features:**\n- Smooth animations\n- Range validation\n- Step controls\n- Number formatting\n- Precision handling\n\n## Utility Components\n\n### JsonViewer / RuleViewer\n\nJSON visualization with syntax highlighting.\n\n```typescript\ninterface JsonViewerProps {\n  data: any;\n  rootName?: string;\n  defaultExpanded?: boolean;\n  className?: string;\n  highlightLogicalOperators?: boolean;\n  collapsible?: boolean;\n  searchable?: boolean;\n}\n```\n\n**Features:**\n- Syntax highlighting\n- Collapsible nodes\n- Search functionality\n- Logical operator highlighting\n- Copy to clipboard\n\n**Example:**\n```tsx\n<JsonViewer\n  data={rule}\n  rootName=\"rule\"\n  defaultExpanded={true}\n  highlightLogicalOperators={true}\n  searchable={true}\n/>\n```\n\n### DiffViewer\n\nRule comparison and diff visualization.\n\n```typescript\ninterface DiffViewerProps {\n  oldValue: any;\n  newValue: any;\n  className?: string;\n  title?: string;\n  oldTitle?: string;\n  newTitle?: string;\n  viewMode?: \"split\" | \"unified\";\n  showStats?: boolean;\n}\n```\n\n**Features:**\n- Side-by-side comparison\n- Unified diff view\n- Change statistics\n- Syntax highlighting\n- Property-level analysis\n\n**Example:**\n```tsx\n<DiffViewer\n  oldValue={previousRule}\n  newValue={currentRule}\n  title=\"Rule Changes\"\n  viewMode=\"split\"\n  showStats={true}\n/>\n```\n\n### ImportExport\n\nRule import/export functionality.\n\n```typescript\ninterface ImportExportProps {\n  onImport: (data: any, format: string) => void;\n  onExport: (format: string) => any;\n  supportedFormats?: string[];\n  className?: string;\n}\n```\n\n**Features:**\n- JSON/YAML support\n- File upload/download\n- Validation on import\n- Format conversion\n- Error handling\n\n### ThemeToggle\n\nLight/dark theme switching.\n\n```typescript\ninterface ThemeToggleProps {\n  className?: string;\n  size?: \"sm\" | \"md\" | \"lg\";\n  showLabel?: boolean;\n}\n```\n\n**Features:**\n- System theme detection\n- Smooth transitions\n- Customizable appearance\n- Accessibility support\n\n## Hook Components\n\n### Enhanced Rule Store\n\nAdvanced state management with history.\n\n```typescript\nconst useEnhancedRuleStore = () => ({\n  // State\n  rule: RuleType;\n  history: HistoryEntry[];\n  historyIndex: number;\n  expandedGroups: Set<string>;\n  \n  // Actions\n  updateRule: (rule: RuleType, action?: string, description?: string) => void;\n  updateConditions: (conditions: Condition[]) => void;\n  setRule: (rule: RuleType, action?: string, description?: string) => void;\n  \n  // History\n  undo: () => void;\n  redo: () => void;\n  canUndo: () => boolean;\n  canRedo: () => boolean;\n  getUndoInfo: () => HistoryInfo;\n  getRedoInfo: () => HistoryInfo;\n  \n  // UI State\n  expandAll: () => void;\n  collapseAll: () => void;\n  toggleGroup: (groupId: string) => void;\n  isGroupExpanded: (groupId: string) => boolean;\n});\n```\n\n### Field Discovery\n\nAutomatic field discovery from sample data.\n\n```typescript\nconst useFieldDiscovery = (data: any, options?: DiscoveryOptions) => ({\n  fields: FieldConfig[];\n  isLoading: boolean;\n  error: Error | null;\n  discover: () => void;\n  addCustomField: (field: FieldConfig) => void;\n  removeField: (fieldName: string) => void;\n  updateField: (fieldName: string, updates: Partial<FieldConfig>) => void;\n});\n\ninterface DiscoveryOptions {\n  maxDepth?: number;\n  includeArrayIndices?: boolean;\n  generateLabels?: boolean;\n  excludePaths?: string[];\n  fieldTypes?: Record<string, string>;\n}\n```\n\n### Keyboard Shortcuts\n\nConfigurable keyboard shortcut management.\n\n```typescript\ninterface ShortcutConfig {\n  key: string;\n  ctrl?: boolean;\n  cmd?: boolean;\n  shift?: boolean;\n  alt?: boolean;\n  handler: () => void;\n  description: string;\n  disabled?: boolean;\n}\n\nconst useKeyboardShortcuts = (shortcuts: ShortcutConfig[]) => {\n  // Registers global keyboard event listeners\n  // Handles platform-specific modifiers (Cmd on Mac, Ctrl on others)\n  // Provides conflict detection and resolution\n};\n```\n\n## UI Components\n\n### Core UI Components\n\nBuilt on Radix UI primitives with full accessibility support:\n\n| Component | Purpose | Features |\n|-----------|---------|----------|\n| `Button` | Actions and triggers | Variants, sizes, loading states |\n| `Input` | Text input | Validation, prefixes, suffixes |\n| `Select` | Dropdown selection | Search, grouping, custom options |\n| `Dialog` | Modal dialogs | Zoom animations, scroll management |\n| `Popover` | Floating content | Auto-positioning, close triggers |\n| `Tooltip` | Help text | Delays, positioning, rich content |\n| `Tabs` | Content organization | Keyboard navigation, indicators |\n| `Card` | Content containers | Headers, footers, actions |\n| `Badge` | Status indicators | Variants, sizes, icons |\n| `Alert` | Notifications | Types, dismissible, actions |\n\n### Advanced UI Components\n\n| Component | Purpose | Features |\n|-----------|---------|----------|\n| `ZoomDialog` | Full-screen editing | Smooth zoom animations |\n| `ScrollArea` | Custom scrollbars | Virtual scrolling, smooth scroll |\n| `Collapsible` | Expandable content | Animations, nested support |\n| `Command` | Command palette | Search, keyboard navigation |\n| `Calendar` | Date selection | Range selection, disabled dates |\n| `Slider` | Range input | Multiple handles, step values |\n| `Switch` | Boolean toggle | Animated, labeled |\n| `Separator` | Visual dividers | Orientation, spacing |\n\n### Layout Components\n\n| Component | Purpose | Features |\n|-----------|---------|----------|\n| `ResizablePanel` | Resizable layouts | Horizontal/vertical, constraints |\n| `Sheet` | Side panels | Slide animations, overlay |\n| `DropdownMenu` | Contextual menus | Submenus, separators, icons |\n| `HoverCard` | Rich tooltips | Delays, rich content, positioning |\n\n## Component Composition Examples\n\n### Custom Rule Builder\n\n```tsx\nimport {\n  RuleBuilderProvider,\n  TreeConditionGroup,\n  FieldSelector,\n  JsonViewer,\n  useEnhancedRuleStore\n} from '@usex/rule-engine-builder';\n\nfunction CustomRuleBuilder() {\n  const { rule, updateRule } = useEnhancedRuleStore();\n  \n  return (\n    <RuleBuilderProvider>\n      <div className=\"grid grid-cols-3 gap-4\">\n        <div className=\"col-span-2\">\n          <TreeConditionGroup\n            condition={rule.conditions}\n            path={[]}\n            depth={0}\n            fields={fields}\n            onUpdate={updateRule}\n          />\n        </div>\n        <div>\n          <JsonViewer\n            data={rule}\n            highlightLogicalOperators={true}\n          />\n        </div>\n      </div>\n    </RuleBuilderProvider>\n  );\n}\n```\n\n### Evaluation Dashboard\n\n```tsx\nimport {\n  TreeRuleBuilder,\n  RuleEvaluator,\n  HistoryViewer,\n  DiffViewer\n} from '@usex/rule-engine-builder';\n\nfunction EvaluationDashboard() {\n  const [rule, setRule] = useState(null);\n  const [testData, setTestData] = useState({});\n  const [selectedVersions, setSelectedVersions] = useState([]);\n  \n  return (\n    <div className=\"space-y-6\">\n      <div className=\"grid grid-cols-2 gap-6\">\n        <TreeRuleBuilder\n          onChange={setRule}\n          sampleData={testData}\n        />\n        <RuleEvaluator\n          rule={rule}\n          data={testData}\n          onDataChange={setTestData}\n        />\n      </div>\n      \n      <div className=\"grid grid-cols-2 gap-6\">\n        <HistoryViewer />\n        {selectedVersions.length === 2 && (\n          <DiffViewer\n            oldValue={selectedVersions[0]}\n            newValue={selectedVersions[1]}\n            title=\"Version Comparison\"\n          />\n        )}\n      </div>\n    </div>\n  );\n}\n```\n\n---\n\nFor more information, see the [main documentation](../README.md)."
  },
  {
    "path": "packages/builder/docs/examples.md",
    "content": "# Examples and Use Cases\n\nComprehensive collection of real-world examples using @usex/rule-engine-builder.\n\n## Table of Contents\n\n- [E-commerce Examples](#e-commerce-examples)\n- [Access Control Examples](#access-control-examples)\n- [Form Validation Examples](#form-validation-examples)\n- [Business Logic Examples](#business-logic-examples)\n- [Data Processing Examples](#data-processing-examples)\n- [Integration Examples](#integration-examples)\n\n## E-commerce Examples\n\n### Dynamic Pricing Rules\n\n```tsx\nimport { TreeRuleBuilder, FieldConfig } from '@usex/rule-engine-builder';\n\nconst pricingFields: FieldConfig[] = [\n  {\n    name: 'product.category',\n    label: 'Product Category',\n    type: 'string',\n    group: 'Product',\n    values: [\n      { value: 'electronics', label: 'Electronics' },\n      { value: 'clothing', label: 'Clothing' },\n      { value: 'books', label: 'Books' },\n      { value: 'home', label: 'Home & Garden' }\n    ]\n  },\n  {\n    name: 'product.price',\n    label: 'Base Price',\n    type: 'number',\n    group: 'Product'\n  },\n  {\n    name: 'customer.tier',\n    label: 'Customer Tier',\n    type: 'string',\n    group: 'Customer',\n    values: [\n      { value: 'bronze', label: 'Bronze' },\n      { value: 'silver', label: 'Silver' },\n      { value: 'gold', label: 'Gold' },\n      { value: 'platinum', label: 'Platinum' }\n    ]\n  },\n  {\n    name: 'order.quantity',\n    label: 'Order Quantity',\n    type: 'number',\n    group: 'Order'\n  },\n  {\n    name: 'order.total',\n    label: 'Order Total',\n    type: 'number',\n    group: 'Order'\n  },\n  {\n    name: 'customer.isFirstTime',\n    label: 'First Time Customer',\n    type: 'boolean',\n    group: 'Customer'\n  },\n  {\n    name: 'season.current',\n    label: 'Current Season',\n    type: 'string',\n    group: 'Context',\n    values: [\n      { value: 'spring', label: 'Spring' },\n      { value: 'summer', label: 'Summer' },\n      { value: 'fall', label: 'Fall' },\n      { value: 'winter', label: 'Winter' }\n    ]\n  }\n];\n\nfunction DynamicPricingBuilder() {\n  const [pricingRule, setPricingRule] = useState(null);\n\n  const sampleData = {\n    product: {\n      category: 'electronics',\n      price: 299.99,\n      name: 'Wireless Headphones'\n    },\n    customer: {\n      tier: 'gold',\n      isFirstTime: false,\n      totalSpent: 1500\n    },\n    order: {\n      quantity: 2,\n      total: 599.98\n    },\n    season: {\n      current: 'winter'\n    }\n  };\n\n  const handlePricingRuleChange = (rule) => {\n    setPricingRule(rule);\n    console.log('Pricing rule updated:', rule);\n  };\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"bg-white p-6 rounded-lg shadow\">\n        <h2 className=\"text-2xl font-bold mb-4\">Dynamic Pricing Rules</h2>\n        <p className=\"text-gray-600 mb-6\">\n          Create rules to automatically adjust pricing based on customer, product, and context factors.\n        </p>\n\n        <TreeRuleBuilder\n          fields={pricingFields}\n          sampleData={sampleData}\n          onChange={handlePricingRuleChange}\n          labels={{\n            addGroup: 'Add Pricing Condition',\n            noRules: 'No pricing rules defined. Add conditions to create dynamic pricing.'\n          }}\n          colors={{\n            and: 'border-green-500/30 bg-green-500/5',\n            or: 'border-blue-500/30 bg-blue-500/5',\n            none: 'border-red-500/30 bg-red-500/5'\n          }}\n        />\n      </div>\n\n      {/* Example rule preview */}\n      <div className=\"bg-gray-50 p-4 rounded-lg\">\n        <h3 className=\"font-semibold mb-2\">Example Pricing Rules:</h3>\n        <ul className=\"text-sm space-y-1\">\n          <li>• Gold/Platinum customers get 15% off electronics over $200</li>\n          <li>• First-time customers get 10% off their first order</li>\n          <li>• Bulk orders (5+ items) get 20% off</li>\n          <li>• Winter season: 25% off clothing items</li>\n        </ul>\n      </div>\n    </div>\n  );\n}\n```\n\n### Shipping Rate Calculator\n\n```tsx\nconst shippingFields: FieldConfig[] = [\n  {\n    name: 'order.weight',\n    label: 'Package Weight (lbs)',\n    type: 'number',\n    group: 'Package'\n  },\n  {\n    name: 'order.dimensions',\n    label: 'Package Dimensions',\n    type: 'object',\n    group: 'Package'\n  },\n  {\n    name: 'destination.country',\n    label: 'Destination Country',\n    type: 'string',\n    group: 'Destination',\n    values: [\n      { value: 'US', label: 'United States' },\n      { value: 'CA', label: 'Canada' },\n      { value: 'MX', label: 'Mexico' },\n      { value: 'UK', label: 'United Kingdom' },\n      { value: 'DE', label: 'Germany' }\n    ]\n  },\n  {\n    name: 'destination.state',\n    label: 'Destination State',\n    type: 'string',\n    group: 'Destination'\n  },\n  {\n    name: 'destination.isRemote',\n    label: 'Remote Location',\n    type: 'boolean',\n    group: 'Destination'\n  },\n  {\n    name: 'shipping.method',\n    label: 'Shipping Method',\n    type: 'string',\n    group: 'Shipping',\n    values: [\n      { value: 'standard', label: 'Standard (5-7 days)' },\n      { value: 'expedited', label: 'Expedited (2-3 days)' },\n      { value: 'overnight', label: 'Overnight' }\n    ]\n  },\n  {\n    name: 'customer.isPremium',\n    label: 'Premium Customer',\n    type: 'boolean',\n    group: 'Customer'\n  }\n];\n\nfunction ShippingCalculatorBuilder() {\n  const sampleData = {\n    order: {\n      weight: 2.5,\n      dimensions: { length: 12, width: 8, height: 6 },\n      value: 199.99\n    },\n    destination: {\n      country: 'US',\n      state: 'CA',\n      zipCode: '90210',\n      isRemote: false\n    },\n    shipping: {\n      method: 'standard'\n    },\n    customer: {\n      isPremium: true\n    }\n  };\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"bg-white p-6 rounded-lg shadow\">\n        <h2 className=\"text-2xl font-bold mb-4\">Shipping Rate Rules</h2>\n\n        <TreeRuleBuilder\n          fields={shippingFields}\n          sampleData={sampleData}\n          onChange={(rule) => console.log('Shipping rule:', rule)}\n          labels={{\n            addGroup: 'Add Shipping Condition',\n            noRules: 'No shipping rules defined. Create rules to calculate shipping rates.'\n          }}\n        />\n      </div>\n\n      {/* Rate examples */}\n      <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n        <div className=\"bg-blue-50 p-4 rounded\">\n          <h4 className=\"font-semibold\">Standard Shipping</h4>\n          <p className=\"text-sm\">$5.99 base + $0.50/lb</p>\n        </div>\n        <div className=\"bg-yellow-50 p-4 rounded\">\n          <h4 className=\"font-semibold\">Expedited Shipping</h4>\n          <p className=\"text-sm\">$12.99 base + $1.00/lb</p>\n        </div>\n        <div className=\"bg-red-50 p-4 rounded\">\n          <h4 className=\"font-semibold\">Overnight Shipping</h4>\n          <p className=\"text-sm\">$24.99 base + $2.00/lb</p>\n        </div>\n      </div>\n    </div>\n  );\n}\n```\n\n### Promotional Campaign Rules\n\n```tsx\nconst promotionFields: FieldConfig[] = [\n  {\n    name: 'campaign.code',\n    label: 'Promotion Code',\n    type: 'string',\n    group: 'Campaign'\n  },\n  {\n    name: 'campaign.startDate',\n    label: 'Campaign Start Date',\n    type: 'date',\n    group: 'Campaign'\n  },\n  {\n    name: 'campaign.endDate',\n    label: 'Campaign End Date',\n    type: 'date',\n    group: 'Campaign'\n  },\n  {\n    name: 'customer.email',\n    label: 'Customer Email',\n    type: 'string',\n    group: 'Customer'\n  },\n  {\n    name: 'customer.previousOrders',\n    label: 'Previous Orders Count',\n    type: 'number',\n    group: 'Customer'\n  },\n  {\n    name: 'order.items',\n    label: 'Order Items',\n    type: 'array',\n    group: 'Order'\n  },\n  {\n    name: 'order.categories',\n    label: 'Product Categories',\n    type: 'array',\n    group: 'Order'\n  }\n];\n\nfunction PromotionalCampaignBuilder() {\n  const sampleData = {\n    campaign: {\n      code: 'SAVE20',\n      startDate: '2025-01-01',\n      endDate: '2025-01-31'\n    },\n    customer: {\n      email: 'customer@example.com',\n      previousOrders: 3,\n      registrationDate: '2023-06-15'\n    },\n    order: {\n      items: ['item1', 'item2', 'item3'],\n      categories: ['electronics', 'accessories'],\n      total: 299.99\n    }\n  };\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"bg-white p-6 rounded-lg shadow\">\n        <h2 className=\"text-2xl font-bold mb-4\">Promotional Campaign Rules</h2>\n        <p className=\"text-gray-600 mb-6\">\n          Define complex promotional rules with multiple conditions and customer targeting.\n        </p>\n\n        <TreeRuleBuilder\n          fields={promotionFields}\n          sampleData={sampleData}\n          onChange={(rule) => console.log('Promotion rule:', rule)}\n          labels={{\n            addGroup: 'Add Promotion Condition',\n            or: 'ANY of these conditions',\n            and: 'ALL of these conditions',\n            none: 'NONE of these conditions'\n          }}\n        />\n      </div>\n\n      {/* Campaign examples */}\n      <div className=\"bg-gradient-to-r from-purple-100 to-pink-100 p-6 rounded-lg\">\n        <h3 className=\"font-semibold mb-4\">Example Campaign Rules:</h3>\n        <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n          <div className=\"bg-white p-4 rounded\">\n            <h4 className=\"font-semibold text-purple-700\">New Customer Welcome</h4>\n            <ul className=\"text-sm mt-2 space-y-1\">\n              <li>• First-time customers only</li>\n              <li>• 20% off first order</li>\n              <li>• Minimum $50 purchase</li>\n            </ul>\n          </div>\n          <div className=\"bg-white p-4 rounded\">\n            <h4 className=\"font-semibold text-pink-700\">Loyalty Rewards</h4>\n            <ul className=\"text-sm mt-2 space-y-1\">\n              <li>• 5+ previous orders</li>\n              <li>• 15% off electronics</li>\n              <li>• Free shipping included</li>\n            </ul>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n```\n\n## Access Control Examples\n\n### Role-Based Access Control (RBAC)\n\n```tsx\nconst rbacFields: FieldConfig[] = [\n  {\n    name: 'user.role',\n    label: 'User Role',\n    type: 'string',\n    group: 'User',\n    values: [\n      { value: 'admin', label: 'Administrator' },\n      { value: 'manager', label: 'Manager' },\n      { value: 'employee', label: 'Employee' },\n      { value: 'contractor', label: 'Contractor' },\n      { value: 'guest', label: 'Guest' }\n    ]\n  },\n  {\n    name: 'user.department',\n    label: 'Department',\n    type: 'string',\n    group: 'User',\n    values: [\n      { value: 'engineering', label: 'Engineering' },\n      { value: 'sales', label: 'Sales' },\n      { value: 'marketing', label: 'Marketing' },\n      { value: 'hr', label: 'Human Resources' },\n      { value: 'finance', label: 'Finance' }\n    ]\n  },\n  {\n    name: 'user.permissions',\n    label: 'User Permissions',\n    type: 'array',\n    group: 'User'\n  },\n  {\n    name: 'resource.type',\n    label: 'Resource Type',\n    type: 'string',\n    group: 'Resource',\n    values: [\n      { value: 'document', label: 'Document' },\n      { value: 'project', label: 'Project' },\n      { value: 'user-profile', label: 'User Profile' },\n      { value: 'financial-data', label: 'Financial Data' },\n      { value: 'system-config', label: 'System Configuration' }\n    ]\n  },\n  {\n    name: 'resource.owner',\n    label: 'Resource Owner',\n    type: 'string',\n    group: 'Resource'\n  },\n  {\n    name: 'resource.confidentiality',\n    label: 'Confidentiality Level',\n    type: 'string',\n    group: 'Resource',\n    values: [\n      { value: 'public', label: 'Public' },\n      { value: 'internal', label: 'Internal' },\n      { value: 'confidential', label: 'Confidential' },\n      { value: 'restricted', label: 'Restricted' }\n    ]\n  },\n  {\n    name: 'action.type',\n    label: 'Action Type',\n    type: 'string',\n    group: 'Action',\n    values: [\n      { value: 'read', label: 'Read' },\n      { value: 'write', label: 'Write' },\n      { value: 'delete', label: 'Delete' },\n      { value: 'share', label: 'Share' },\n      { value: 'export', label: 'Export' }\n    ]\n  },\n  {\n    name: 'context.time',\n    label: 'Access Time',\n    type: 'string',\n    group: 'Context'\n  },\n  {\n    name: 'context.location',\n    label: 'Access Location',\n    type: 'string',\n    group: 'Context'\n  }\n];\n\nfunction RBACBuilder() {\n  const sampleData = {\n    user: {\n      id: 'user123',\n      role: 'manager',\n      department: 'engineering',\n      permissions: ['read', 'write', 'manage-team'],\n      clearanceLevel: 3\n    },\n    resource: {\n      id: 'doc456',\n      type: 'document',\n      owner: 'user789',\n      confidentiality: 'internal',\n      department: 'engineering'\n    },\n    action: {\n      type: 'read'\n    },\n    context: {\n      time: '14:30',\n      location: 'office',\n      ipAddress: '192.168.1.100'\n    }\n  };\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"bg-white p-6 rounded-lg shadow\">\n        <h2 className=\"text-2xl font-bold mb-4\">Access Control Rules</h2>\n        <p className=\"text-gray-600 mb-6\">\n          Define role-based access control rules with fine-grained permissions.\n        </p>\n\n        <TreeRuleBuilder\n          fields={rbacFields}\n          sampleData={sampleData}\n          onChange={(rule) => console.log('Access rule:', rule)}\n          labels={{\n            addGroup: 'Add Access Condition',\n            noRules: 'No access rules defined. Create rules to control resource access.'\n          }}\n          colors={{\n            and: 'border-green-500/30 bg-green-500/5',\n            or: 'border-orange-500/30 bg-orange-500/5',\n            none: 'border-red-500/30 bg-red-500/5'\n          }}\n        />\n      </div>\n\n      {/* Access examples */}\n      <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n        <div className=\"bg-green-50 p-4 rounded border border-green-200\">\n          <h4 className=\"font-semibold text-green-800\">Admin Access</h4>\n          <ul className=\"text-sm mt-2 space-y-1 text-green-700\">\n            <li>• Full system access</li>\n            <li>• All resource types</li>\n            <li>• All actions allowed</li>\n          </ul>\n        </div>\n        <div className=\"bg-blue-50 p-4 rounded border border-blue-200\">\n          <h4 className=\"font-semibold text-blue-800\">Manager Access</h4>\n          <ul className=\"text-sm mt-2 space-y-1 text-blue-700\">\n            <li>• Department resources</li>\n            <li>• Team management</li>\n            <li>• Read/Write permissions</li>\n          </ul>\n        </div>\n        <div className=\"bg-gray-50 p-4 rounded border border-gray-200\">\n          <h4 className=\"font-semibold text-gray-800\">Employee Access</h4>\n          <ul className=\"text-sm mt-2 space-y-1 text-gray-700\">\n            <li>• Own resources only</li>\n            <li>• Public documents</li>\n            <li>• Limited actions</li>\n          </ul>\n        </div>\n      </div>\n    </div>\n  );\n}\n```\n\n### Multi-Factor Authentication Rules\n\n```tsx\nconst mfaFields: FieldConfig[] = [\n  {\n    name: 'user.riskScore',\n    label: 'User Risk Score',\n    type: 'number',\n    group: 'User',\n    description: 'Calculated risk score from 0-100'\n  },\n  {\n    name: 'device.trusted',\n    label: 'Trusted Device',\n    type: 'boolean',\n    group: 'Device'\n  },\n  {\n    name: 'location.knownLocation',\n    label: 'Known Location',\n    type: 'boolean',\n    group: 'Location'\n  },\n  {\n    name: 'location.country',\n    label: 'Country',\n    type: 'string',\n    group: 'Location'\n  },\n  {\n    name: 'session.lastLogin',\n    label: 'Last Login',\n    type: 'date',\n    group: 'Session'\n  },\n  {\n    name: 'action.sensitivity',\n    label: 'Action Sensitivity',\n    type: 'string',\n    group: 'Action',\n    values: [\n      { value: 'low', label: 'Low' },\n      { value: 'medium', label: 'Medium' },\n      { value: 'high', label: 'High' },\n      { value: 'critical', label: 'Critical' }\n    ]\n  }\n];\n\nfunction MFABuilder() {\n  const sampleData = {\n    user: {\n      id: 'user123',\n      riskScore: 25,\n      hasActiveMFA: true\n    },\n    device: {\n      id: 'device456',\n      trusted: true,\n      type: 'mobile'\n    },\n    location: {\n      knownLocation: false,\n      country: 'US',\n      ipAddress: '203.0.113.1'\n    },\n    session: {\n      lastLogin: '2025-01-15T10:30:00Z',\n      duration: 30\n    },\n    action: {\n      type: 'transfer-funds',\n      sensitivity: 'critical'\n    }\n  };\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"bg-white p-6 rounded-lg shadow\">\n        <h2 className=\"text-2xl font-bold mb-4\">Multi-Factor Authentication Rules</h2>\n        <p className=\"text-gray-600 mb-6\">\n          Create intelligent MFA rules based on risk assessment and context.\n        </p>\n\n        <TreeRuleBuilder\n          fields={mfaFields}\n          sampleData={sampleData}\n          onChange={(rule) => console.log('MFA rule:', rule)}\n          labels={{\n            addGroup: 'Add MFA Condition'\n          }}\n        />\n      </div>\n\n      {/* MFA scenarios */}\n      <div className=\"bg-yellow-50 p-6 rounded-lg border border-yellow-200\">\n        <h3 className=\"font-semibold mb-4 text-yellow-800\">MFA Trigger Scenarios:</h3>\n        <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n          <div className=\"space-y-2\">\n            <h4 className=\"font-medium\">High Risk Scenarios:</h4>\n            <ul className=\"text-sm space-y-1\">\n              <li>• Unknown device or location</li>\n              <li>• High-sensitivity actions</li>\n              <li>• Elevated risk score (&gt; 50)</li>\n              <li>• International access</li>\n            </ul>\n          </div>\n          <div className=\"space-y-2\">\n            <h4 className=\"font-medium\">Low Risk Scenarios:</h4>\n            <ul className=\"text-sm space-y-1\">\n              <li>• Trusted device + known location</li>\n              <li>• Low-sensitivity actions</li>\n              <li>• Recent successful authentication</li>\n              <li>• Low risk score (&lt; 20)</li>\n            </ul>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n```\n\n## Form Validation Examples\n\n### User Registration Validation\n\n```tsx\nconst registrationFields: FieldConfig[] = [\n  {\n    name: 'email',\n    label: 'Email Address',\n    type: 'string',\n    group: 'Contact'\n  },\n  {\n    name: 'password',\n    label: 'Password',\n    type: 'string',\n    group: 'Security'\n  },\n  {\n    name: 'confirmPassword',\n    label: 'Confirm Password',\n    type: 'string',\n    group: 'Security'\n  },\n  {\n    name: 'firstName',\n    label: 'First Name',\n    type: 'string',\n    group: 'Personal'\n  },\n  {\n    name: 'lastName',\n    label: 'Last Name',\n    type: 'string',\n    group: 'Personal'\n  },\n  {\n    name: 'age',\n    label: 'Age',\n    type: 'number',\n    group: 'Personal'\n  },\n  {\n    name: 'phoneNumber',\n    label: 'Phone Number',\n    type: 'string',\n    group: 'Contact'\n  },\n  {\n    name: 'acceptTerms',\n    label: 'Accept Terms',\n    type: 'boolean',\n    group: 'Legal'\n  },\n  {\n    name: 'marketingConsent',\n    label: 'Marketing Consent',\n    type: 'boolean',\n    group: 'Legal'\n  }\n];\n\nfunction RegistrationValidationBuilder() {\n  const [validationRule, setValidationRule] = useState(null);\n  const [formData, setFormData] = useState({\n    email: 'user@example.com',\n    password: 'securePass123!',\n    confirmPassword: 'securePass123!',\n    firstName: 'John',\n    lastName: 'Doe',\n    age: 25,\n    phoneNumber: '+1-555-0123',\n    acceptTerms: true,\n    marketingConsent: false\n  });\n\n  const validateForm = async (data) => {\n    if (!validationRule) return { isValid: true, errors: [] };\n\n    try {\n      const result = await RuleEngine.evaluate(validationRule, data);\n      return {\n        isValid: result.isPassed,\n        errors: result.isPassed ? [] : ['Validation failed']\n      };\n    } catch (error) {\n      return {\n        isValid: false,\n        errors: [error.message]\n      };\n    }\n  };\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"bg-white p-6 rounded-lg shadow\">\n        <h2 className=\"text-2xl font-bold mb-4\">Registration Validation Rules</h2>\n        <p className=\"text-gray-600 mb-6\">\n          Create comprehensive validation rules for user registration forms.\n        </p>\n\n        <TreeRuleBuilder\n          fields={registrationFields}\n          sampleData={formData}\n          onChange={setValidationRule}\n          labels={{\n            addGroup: 'Add Validation Rule',\n            noRules: 'No validation rules defined. Add rules to validate form fields.'\n          }}\n        />\n      </div>\n\n      {/* Form testing */}\n      <div className=\"bg-gray-50 p-6 rounded-lg\">\n        <h3 className=\"font-semibold mb-4\">Test Validation</h3>\n        <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n          <div>\n            <h4 className=\"font-medium mb-2\">Sample Form Data:</h4>\n            <pre className=\"text-xs bg-white p-3 rounded border overflow-auto\">\n              {JSON.stringify(formData, null, 2)}\n            </pre>\n          </div>\n          <div>\n            <h4 className=\"font-medium mb-2\">Validation Rules:</h4>\n            <ul className=\"text-sm space-y-1\">\n              <li>• Email must be valid format</li>\n              <li>• Password minimum 8 characters</li>\n              <li>• Password must contain uppercase, lowercase, number, symbol</li>\n              <li>• Passwords must match</li>\n              <li>• Age must be 18 or older</li>\n              <li>• Terms must be accepted</li>\n            </ul>\n          </div>\n        </div>\n\n        <button\n          onClick={() => validateForm(formData)}\n          className=\"mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600\"\n        >\n          Validate Form\n        </button>\n      </div>\n    </div>\n  );\n}\n```\n\n### Dynamic Form Validation\n\n```tsx\nconst dynamicValidationFields: FieldConfig[] = [\n  {\n    name: 'field.name',\n    label: 'Field Name',\n    type: 'string',\n    group: 'Field'\n  },\n  {\n    name: 'field.type',\n    label: 'Field Type',\n    type: 'string',\n    group: 'Field',\n    values: [\n      { value: 'text', label: 'Text' },\n      { value: 'email', label: 'Email' },\n      { value: 'number', label: 'Number' },\n      { value: 'date', label: 'Date' },\n      { value: 'select', label: 'Select' },\n      { value: 'checkbox', label: 'Checkbox' }\n    ]\n  },\n  {\n    name: 'field.required',\n    label: 'Required Field',\n    type: 'boolean',\n    group: 'Field'\n  },\n  {\n    name: 'field.value',\n    label: 'Field Value',\n    type: 'string',\n    group: 'Field'\n  },\n  {\n    name: 'form.step',\n    label: 'Form Step',\n    type: 'number',\n    group: 'Form'\n  },\n  {\n    name: 'user.role',\n    label: 'User Role',\n    type: 'string',\n    group: 'Context',\n    values: [\n      { value: 'admin', label: 'Administrator' },\n      { value: 'user', label: 'Regular User' },\n      { value: 'guest', label: 'Guest' }\n    ]\n  }\n];\n\nfunction DynamicValidationBuilder() {\n  const sampleData = {\n    field: {\n      name: 'businessLicense',\n      type: 'text',\n      required: true,\n      value: 'BL123456789'\n    },\n    form: {\n      step: 2,\n      totalSteps: 4,\n      category: 'business-registration'\n    },\n    user: {\n      role: 'user',\n      accountType: 'business'\n    }\n  };\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"bg-white p-6 rounded-lg shadow\">\n        <h2 className=\"text-2xl font-bold mb-4\">Dynamic Form Validation</h2>\n        <p className=\"text-gray-600 mb-6\">\n          Create conditional validation rules that adapt based on form context and user role.\n        </p>\n\n        <TreeRuleBuilder\n          fields={dynamicValidationFields}\n          sampleData={sampleData}\n          onChange={(rule) => console.log('Dynamic validation rule:', rule)}\n          labels={{\n            addGroup: 'Add Conditional Validation'\n          }}\n        />\n      </div>\n\n      {/* Validation scenarios */}\n      <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n        <div className=\"bg-blue-50 p-4 rounded border border-blue-200\">\n          <h4 className=\"font-semibold text-blue-800 mb-2\">Step-Based Validation</h4>\n          <ul className=\"text-sm space-y-1 text-blue-700\">\n            <li>• Step 1: Basic info required</li>\n            <li>• Step 2: Business details (if business account)</li>\n            <li>• Step 3: Payment info (if paid plan)</li>\n            <li>• Step 4: Final verification</li>\n          </ul>\n        </div>\n        <div className=\"bg-green-50 p-4 rounded border border-green-200\">\n          <h4 className=\"font-semibold text-green-800 mb-2\">Role-Based Validation</h4>\n          <ul className=\"text-sm space-y-1 text-green-700\">\n            <li>• Admin: All fields optional</li>\n            <li>• Business: Additional docs required</li>\n            <li>• Individual: Simplified validation</li>\n            <li>• Guest: Limited access</li>\n          </ul>\n        </div>\n      </div>\n    </div>\n  );\n}\n```\n\n## Business Logic Examples\n\n### Lead Scoring System\n\n```tsx\nconst leadScoringFields: FieldConfig[] = [\n  {\n    name: 'company.size',\n    label: 'Company Size',\n    type: 'string',\n    group: 'Company',\n    values: [\n      { value: 'startup', label: 'Startup (1-10 employees)' },\n      { value: 'small', label: 'Small (11-50 employees)' },\n      { value: 'medium', label: 'Medium (51-200 employees)' },\n      { value: 'large', label: 'Large (201-1000 employees)' },\n      { value: 'enterprise', label: 'Enterprise (1000+ employees)' }\n    ]\n  },\n  {\n    name: 'company.industry',\n    label: 'Industry',\n    type: 'string',\n    group: 'Company',\n    values: [\n      { value: 'technology', label: 'Technology' },\n      { value: 'finance', label: 'Finance' },\n      { value: 'healthcare', label: 'Healthcare' },\n      { value: 'retail', label: 'Retail' },\n      { value: 'manufacturing', label: 'Manufacturing' }\n    ]\n  },\n  {\n    name: 'company.revenue',\n    label: 'Annual Revenue',\n    type: 'number',\n    group: 'Company'\n  },\n  {\n    name: 'contact.title',\n    label: 'Job Title',\n    type: 'string',\n    group: 'Contact',\n    values: [\n      { value: 'ceo', label: 'CEO' },\n      { value: 'cto', label: 'CTO' },\n      { value: 'vp', label: 'VP' },\n      { value: 'director', label: 'Director' },\n      { value: 'manager', label: 'Manager' },\n      { value: 'individual', label: 'Individual Contributor' }\n    ]\n  },\n  {\n    name: 'engagement.emailOpens',\n    label: 'Email Opens (30 days)',\n    type: 'number',\n    group: 'Engagement'\n  },\n  {\n    name: 'engagement.websiteVisits',\n    label: 'Website Visits (30 days)',\n    type: 'number',\n    group: 'Engagement'\n  },\n  {\n    name: 'engagement.contentDownloads',\n    label: 'Content Downloads',\n    type: 'number',\n    group: 'Engagement'\n  },\n  {\n    name: 'behavior.demoRequested',\n    label: 'Demo Requested',\n    type: 'boolean',\n    group: 'Behavior'\n  },\n  {\n    name: 'behavior.pricingPageViews',\n    label: 'Pricing Page Views',\n    type: 'number',\n    group: 'Behavior'\n  }\n];\n\nfunction LeadScoringBuilder() {\n  const sampleData = {\n    company: {\n      size: 'medium',\n      industry: 'technology',\n      revenue: 5000000,\n      location: 'US'\n    },\n    contact: {\n      title: 'cto',\n      email: 'cto@example.com',\n      firstName: 'Jane',\n      lastName: 'Smith'\n    },\n    engagement: {\n      emailOpens: 8,\n      websiteVisits: 15,\n      contentDownloads: 3\n    },\n    behavior: {\n      demoRequested: true,\n      pricingPageViews: 5,\n      trialStarted: false\n    }\n  };\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"bg-white p-6 rounded-lg shadow\">\n        <h2 className=\"text-2xl font-bold mb-4\">Lead Scoring Rules</h2>\n        <p className=\"text-gray-600 mb-6\">\n          Create intelligent lead scoring based on company fit and engagement metrics.\n        </p>\n\n        <TreeRuleBuilder\n          fields={leadScoringFields}\n          sampleData={sampleData}\n          onChange={(rule) => console.log('Lead scoring rule:', rule)}\n          labels={{\n            addGroup: 'Add Scoring Condition'\n          }}\n        />\n      </div>\n\n      {/* Scoring matrix */}\n      <div className=\"bg-gradient-to-r from-blue-50 to-indigo-50 p-6 rounded-lg\">\n        <h3 className=\"font-semibold mb-4\">Lead Scoring Matrix</h3>\n        <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4\">\n          <div className=\"bg-white p-4 rounded shadow\">\n            <h4 className=\"font-semibold text-red-600\">Cold Lead (0-25)</h4>\n            <ul className=\"text-sm mt-2 space-y-1\">\n              <li>• Small company</li>\n              <li>• Low engagement</li>\n              <li>• No demo interest</li>\n            </ul>\n          </div>\n          <div className=\"bg-white p-4 rounded shadow\">\n            <h4 className=\"font-semibold text-yellow-600\">Warm Lead (26-50)</h4>\n            <ul className=\"text-sm mt-2 space-y-1\">\n              <li>• Medium company</li>\n              <li>• Some engagement</li>\n              <li>• Content downloads</li>\n            </ul>\n          </div>\n          <div className=\"bg-white p-4 rounded shadow\">\n            <h4 className=\"font-semibold text-orange-600\">Hot Lead (51-75)</h4>\n            <ul className=\"text-sm mt-2 space-y-1\">\n              <li>• Large company</li>\n              <li>• High engagement</li>\n              <li>• Pricing interest</li>\n            </ul>\n          </div>\n          <div className=\"bg-white p-4 rounded shadow\">\n            <h4 className=\"font-semibold text-green-600\">Qualified Lead (76-100)</h4>\n            <ul className=\"text-sm mt-2 space-y-1\">\n              <li>• Enterprise company</li>\n              <li>• Decision maker</li>\n              <li>• Demo requested</li>\n            </ul>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n```\n\n### Inventory Management Rules\n\n```tsx\nconst inventoryFields: FieldConfig[] = [\n  {\n    name: 'product.sku',\n    label: 'Product SKU',\n    type: 'string',\n    group: 'Product'\n  },\n  {\n    name: 'product.category',\n    label: 'Product Category',\n    type: 'string',\n    group: 'Product'\n  },\n  {\n    name: 'inventory.currentStock',\n    label: 'Current Stock',\n    type: 'number',\n    group: 'Inventory'\n  },\n  {\n    name: 'inventory.minimumStock',\n    label: 'Minimum Stock Level',\n    type: 'number',\n    group: 'Inventory'\n  },\n  {\n    name: 'inventory.maximumStock',\n    label: 'Maximum Stock Level',\n    type: 'number',\n    group: 'Inventory'\n  },\n  {\n    name: 'sales.velocity',\n    label: 'Sales Velocity (units/day)',\n    type: 'number',\n    group: 'Sales'\n  },\n  {\n    name: 'sales.trend',\n    label: 'Sales Trend',\n    type: 'string',\n    group: 'Sales',\n    values: [\n      { value: 'increasing', label: 'Increasing' },\n      { value: 'stable', label: 'Stable' },\n      { value: 'decreasing', label: 'Decreasing' }\n    ]\n  },\n  {\n    name: 'supplier.leadTime',\n    label: 'Supplier Lead Time (days)',\n    type: 'number',\n    group: 'Supplier'\n  },\n  {\n    name: 'season.current',\n    label: 'Current Season',\n    type: 'string',\n    group: 'Context'\n  }\n];\n\nfunction InventoryManagementBuilder() {\n  const sampleData = {\n    product: {\n      sku: 'WH-001',\n      category: 'electronics',\n      name: 'Wireless Headphones'\n    },\n    inventory: {\n      currentStock: 15,\n      minimumStock: 10,\n      maximumStock: 100,\n      warehouseLocation: 'A1-B2'\n    },\n    sales: {\n      velocity: 2.5,\n      trend: 'increasing',\n      lastWeekSales: 18\n    },\n    supplier: {\n      leadTime: 7,\n      reliability: 0.95,\n      cost: 45.00\n    },\n    season: {\n      current: 'holiday'\n    }\n  };\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"bg-white p-6 rounded-lg shadow\">\n        <h2 className=\"text-2xl font-bold mb-4\">Inventory Management Rules</h2>\n        <p className=\"text-gray-600 mb-6\">\n          Automate inventory decisions with intelligent reordering and stock level management.\n        </p>\n\n        <TreeRuleBuilder\n          fields={inventoryFields}\n          sampleData={sampleData}\n          onChange={(rule) => console.log('Inventory rule:', rule)}\n          labels={{\n            addGroup: 'Add Inventory Condition'\n          }}\n        />\n      </div>\n\n      {/* Inventory actions */}\n      <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n        <div className=\"bg-red-50 p-4 rounded border border-red-200\">\n          <h4 className=\"font-semibold text-red-800\">Reorder Alert</h4>\n          <ul className=\"text-sm mt-2 space-y-1 text-red-700\">\n            <li>• Stock below minimum</li>\n            <li>• High sales velocity</li>\n            <li>• Long supplier lead time</li>\n          </ul>\n        </div>\n        <div className=\"bg-yellow-50 p-4 rounded border border-yellow-200\">\n          <h4 className=\"font-semibold text-yellow-800\">Overstock Warning</h4>\n          <ul className=\"text-sm mt-2 space-y-1 text-yellow-700\">\n            <li>• Stock above maximum</li>\n            <li>• Decreasing sales trend</li>\n            <li>• Season ending</li>\n          </ul>\n        </div>\n        <div className=\"bg-green-50 p-4 rounded border border-green-200\">\n          <h4 className=\"font-semibold text-green-800\">Optimal Stock</h4>\n          <ul className=\"text-sm mt-2 space-y-1 text-green-700\">\n            <li>• Between min/max levels</li>\n            <li>• Stable sales trend</li>\n            <li>• Adequate supply buffer</li>\n          </ul>\n        </div>\n      </div>\n    </div>\n  );\n}\n```\n\n## Integration Examples\n\n### Complete E-commerce Platform\n\n```tsx\nfunction EcommercePlatformDemo() {\n  const [activeTab, setActiveTab] = useState('pricing');\n\n  return (\n    <div className=\"min-h-screen bg-gray-50\">\n      <div className=\"container mx-auto py-8\">\n        <h1 className=\"text-3xl font-bold text-center mb-8\">\n          E-commerce Rule Engine Platform\n        </h1>\n\n        <div className=\"bg-white rounded-lg shadow-lg\">\n          <div className=\"border-b border-gray-200\">\n            <nav className=\"flex space-x-8 px-6\">\n              {[\n                { id: 'pricing', label: 'Dynamic Pricing' },\n                { id: 'shipping', label: 'Shipping Rules' },\n                { id: 'promotions', label: 'Promotions' },\n                { id: 'inventory', label: 'Inventory' }\n              ].map((tab) => (\n                <button\n                  key={tab.id}\n                  onClick={() => setActiveTab(tab.id)}\n                  className={`py-4 px-1 border-b-2 font-medium text-sm ${\n                    activeTab === tab.id\n                      ? 'border-blue-500 text-blue-600'\n                      : 'border-transparent text-gray-500 hover:text-gray-700'\n                  }`}\n                >\n                  {tab.label}\n                </button>\n              ))}\n            </nav>\n          </div>\n\n          <div className=\"p-6\">\n            {activeTab === 'pricing' && <DynamicPricingBuilder />}\n            {activeTab === 'shipping' && <ShippingCalculatorBuilder />}\n            {activeTab === 'promotions' && <PromotionalCampaignBuilder />}\n            {activeTab === 'inventory' && <InventoryManagementBuilder />}\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n```\n\n### Multi-tenant SaaS Platform\n\n```tsx\nfunction SaaSRulePlatform() {\n  const [tenant, setTenant] = useState('tenant1');\n  const [ruleType, setRuleType] = useState('access');\n\n  const tenantData = {\n    tenant1: {\n      name: 'Acme Corp',\n      plan: 'enterprise',\n      features: ['advanced-rules', 'api-access', 'audit-logs']\n    },\n    tenant2: {\n      name: 'StartupXYZ',\n      plan: 'pro',\n      features: ['basic-rules', 'api-access']\n    }\n  };\n\n  return (\n    <div className=\"min-h-screen bg-gray-100\">\n      <header className=\"bg-white shadow\">\n        <div className=\"container mx-auto px-6 py-4\">\n          <div className=\"flex items-center justify-between\">\n            <h1 className=\"text-2xl font-bold\">SaaS Rule Engine</h1>\n            <div className=\"flex items-center space-x-4\">\n              <select\n                value={tenant}\n                onChange={(e) => setTenant(e.target.value)}\n                className=\"border rounded px-3 py-2\"\n              >\n                <option value=\"tenant1\">Acme Corp</option>\n                <option value=\"tenant2\">StartupXYZ</option>\n              </select>\n              <select\n                value={ruleType}\n                onChange={(e) => setRuleType(e.target.value)}\n                className=\"border rounded px-3 py-2\"\n              >\n                <option value=\"access\">Access Control</option>\n                <option value=\"validation\">Validation</option>\n                <option value=\"pricing\">Pricing</option>\n              </select>\n            </div>\n          </div>\n        </div>\n      </header>\n\n      <main className=\"container mx-auto py-8 px-6\">\n        <div className=\"bg-white rounded-lg shadow p-6\">\n          <div className=\"mb-6\">\n            <h2 className=\"text-xl font-semibold\">\n              {tenantData[tenant].name} - {ruleType.charAt(0).toUpperCase() + ruleType.slice(1)} Rules\n            </h2>\n            <p className=\"text-gray-600\">\n              Plan: {tenantData[tenant].plan} | Features: {tenantData[tenant].features.join(', ')}\n            </p>\n          </div>\n\n          {ruleType === 'access' && <RBACBuilder />}\n          {ruleType === 'validation' && <RegistrationValidationBuilder />}\n          {ruleType === 'pricing' && <DynamicPricingBuilder />}\n        </div>\n      </main>\n    </div>\n  );\n}\n```\n\n---\n\nFor more examples and detailed implementation guides, see the [main documentation](../README.md).\n"
  },
  {
    "path": "packages/builder/docs/hooks.md",
    "content": "# Hooks Reference\n\nComprehensive guide to all hooks available in @usex/rule-engine-builder.\n\n## Table of Contents\n\n- [State Management Hooks](#state-management-hooks)\n- [UI Interaction Hooks](#ui-interaction-hooks)\n- [Utility Hooks](#utility-hooks)\n- [Custom Hook Patterns](#custom-hook-patterns)\n\n## State Management Hooks\n\n### useEnhancedRuleStore\n\nAdvanced rule state management with history and undo/redo functionality.\n\n```typescript\ninterface EnhancedRuleStore {\n  // Current State\n  rule: RuleType;\n  history: HistoryEntry[];\n  historyIndex: number;\n  expandedGroups: Set<string>;\n  \n  // Rule Management\n  updateRule: (rule: RuleType, action?: string, description?: string) => void;\n  updateConditions: (conditions: Condition[]) => void;\n  setRule: (rule: RuleType, action?: string, description?: string) => void;\n  \n  // History Operations\n  undo: () => void;\n  redo: () => void;\n  canUndo: () => boolean;\n  canRedo: () => boolean;\n  getUndoInfo: () => HistoryInfo | null;\n  getRedoInfo: () => HistoryInfo | null;\n  getHistoryInfo: () => { current: number; total: number };\n  \n  // UI State Management\n  expandAll: () => void;\n  collapseAll: () => void;\n  toggleGroup: (groupId: string) => void;\n  isGroupExpanded: (groupId: string) => boolean;\n  \n  // Utilities\n  clearHistory: () => void;\n  exportHistory: () => HistoryEntry[];\n  importHistory: (history: HistoryEntry[]) => void;\n}\n\ninterface HistoryEntry {\n  rule: RuleType;\n  timestamp: number;\n  action: string;\n  description: string;\n  changes?: {\n    before: any;\n    after: any;\n  };\n}\n```\n\n**Usage:**\n```tsx\nimport { useEnhancedRuleStore } from '@usex/rule-engine-builder';\n\nfunction RuleEditor() {\n  const {\n    rule,\n    updateRule,\n    undo,\n    redo,\n    canUndo,\n    canRedo,\n    getHistoryInfo\n  } = useEnhancedRuleStore();\n  \n  const handleAddCondition = () => {\n    const newRule = {\n      ...rule,\n      conditions: [\n        ...(Array.isArray(rule.conditions) ? rule.conditions : [rule.conditions]),\n        { and: [] }\n      ]\n    };\n    \n    updateRule(newRule, 'Add', 'Added new condition group');\n  };\n  \n  const historyInfo = getHistoryInfo();\n  \n  return (\n    <div>\n      <div className=\"flex gap-2 mb-4\">\n        <button onClick={undo} disabled={!canUndo()}>\n          Undo\n        </button>\n        <button onClick={redo} disabled={!canRedo()}>\n          Redo\n        </button>\n        <span className=\"text-sm text-muted-foreground\">\n          {historyInfo.current} / {historyInfo.total}\n        </span>\n      </div>\n      \n      <button onClick={handleAddCondition}>\n        Add Condition\n      </button>\n      \n      {/* Rule builder UI */}\n    </div>\n  );\n}\n```\n\n**Features:**\n- **History Management**: 100-entry history with automatic cleanup\n- **Action Tracking**: Named actions with descriptions for clear audit trail\n- **Change Detection**: Automatic before/after change tracking\n- **UI State**: Persistent expand/collapse state for rule groups\n- **Export/Import**: Full history serialization support\n\n### useRuleStore\n\nBasic rule state management for simpler use cases.\n\n```typescript\ninterface RuleStore {\n  rule: RuleType;\n  setRule: (rule: RuleType) => void;\n  updateConditions: (conditions: Condition[]) => void;\n  reset: () => void;\n}\n```\n\n**Usage:**\n```tsx\nimport { useRuleStore } from '@usex/rule-engine-builder';\n\nfunction SimpleRuleEditor() {\n  const { rule, setRule, updateConditions } = useRuleStore();\n  \n  return (\n    <div>\n      {/* Simple rule editing UI */}\n    </div>\n  );\n}\n```\n\n## UI Interaction Hooks\n\n### useFieldDiscovery\n\nAutomatic field discovery from sample data with intelligent type inference.\n\n```typescript\ninterface FieldDiscoveryOptions {\n  maxDepth?: number;              // Maximum object nesting depth (default: 5)\n  includeArrayIndices?: boolean;  // Include array index paths (default: false)\n  generateLabels?: boolean;       // Auto-generate human-readable labels (default: true)\n  excludePaths?: string[];        // Paths to exclude from discovery\n  fieldTypes?: Record<string, FieldType>; // Override field types\n  groupBy?: 'path' | 'type' | 'custom'; // Grouping strategy\n  customGrouper?: (field: FieldConfig) => string; // Custom grouping function\n}\n\ninterface FieldDiscoveryResult {\n  fields: FieldConfig[];\n  isLoading: boolean;\n  error: Error | null;\n  stats: {\n    totalFields: number;\n    byType: Record<FieldType, number>;\n    byGroup: Record<string, number>;\n  };\n  \n  // Actions\n  discover: (data: any, options?: FieldDiscoveryOptions) => void;\n  addCustomField: (field: FieldConfig) => void;\n  removeField: (fieldName: string) => void;\n  updateField: (fieldName: string, updates: Partial<FieldConfig>) => void;\n  clearFields: () => void;\n  \n  // Utilities\n  findField: (name: string) => FieldConfig | undefined;\n  getFieldsByGroup: (group: string) => FieldConfig[];\n  getFieldsByType: (type: FieldType) => FieldConfig[];\n  exportFields: () => FieldConfig[];\n  importFields: (fields: FieldConfig[]) => void;\n}\n```\n\n**Usage:**\n```tsx\nimport { useFieldDiscovery } from '@usex/rule-engine-builder';\n\nfunction SmartRuleBuilder() {\n  const {\n    fields,\n    isLoading,\n    discover,\n    addCustomField,\n    stats\n  } = useFieldDiscovery();\n  \n  const sampleData = {\n    user: {\n      name: 'John Doe',\n      age: 30,\n      email: 'john@example.com',\n      preferences: {\n        theme: 'dark',\n        notifications: true\n      }\n    },\n    orders: [\n      { id: 1, total: 99.99, status: 'completed' },\n      { id: 2, total: 149.99, status: 'pending' }\n    ]\n  };\n  \n  useEffect(() => {\n    discover(sampleData, {\n      maxDepth: 3,\n      includeArrayIndices: true,\n      generateLabels: true,\n      groupBy: 'path'\n    });\n  }, [sampleData]);\n  \n  const handleAddCustomField = () => {\n    addCustomField({\n      name: 'customCalculation',\n      label: 'Custom Calculation',\n      type: 'number',\n      group: 'Calculated Fields',\n      description: 'Custom business logic calculation'\n    });\n  };\n  \n  if (isLoading) return <div>Discovering fields...</div>;\n  \n  return (\n    <div>\n      <div className=\"mb-4\">\n        <h3>Discovered Fields ({stats.totalFields})</h3>\n        <div className=\"text-sm text-muted-foreground\">\n          {Object.entries(stats.byType).map(([type, count]) => (\n            <span key={type} className=\"mr-4\">\n              {type}: {count}\n            </span>\n          ))}\n        </div>\n      </div>\n      \n      <button onClick={handleAddCustomField}>\n        Add Custom Field\n      </button>\n      \n      <TreeRuleBuilder\n        fields={fields}\n        sampleData={sampleData}\n      />\n    </div>\n  );\n}\n```\n\n**Field Discovery Algorithm:**\n1. **Traversal**: Deep object traversal with cycle detection\n2. **Type Inference**: Smart type detection based on value analysis\n3. **Label Generation**: Humanized labels from camelCase/snake_case paths\n4. **Grouping**: Automatic grouping by object hierarchy\n5. **Validation**: Field validation and conflict resolution\n\n### useKeyboardShortcuts\n\nComprehensive keyboard shortcut management with platform detection.\n\n```typescript\ninterface ShortcutConfig {\n  key: string;                    // Key to press (case-insensitive)\n  ctrl?: boolean;                // Ctrl key (Windows/Linux)\n  cmd?: boolean;                 // Cmd key (macOS) - auto-maps to ctrl on other platforms\n  shift?: boolean;               // Shift key\n  alt?: boolean;                 // Alt/Option key\n  meta?: boolean;                // Meta key (Windows key, Cmd key)\n  handler: (event: KeyboardEvent) => void; // Handler function\n  description: string;           // Human-readable description\n  disabled?: boolean;            // Temporarily disable shortcut\n  preventDefault?: boolean;      // Prevent default browser behavior (default: true)\n  stopPropagation?: boolean;     // Stop event propagation (default: true)\n  target?: string | Element;     // Specific element to bind to (default: document)\n}\n\ninterface KeyboardShortcutsAPI {\n  register: (shortcuts: ShortcutConfig[]) => void;\n  unregister: (keys: string[]) => void;\n  enable: (key: string) => void;\n  disable: (key: string) => void;\n  getRegistered: () => ShortcutConfig[];\n  isEnabled: (key: string) => boolean;\n}\n```\n\n**Usage:**\n```tsx\nimport { useKeyboardShortcuts } from '@usex/rule-engine-builder';\n\nfunction RuleBuilderWithShortcuts() {\n  const { rule, updateRule, undo, redo, canUndo, canRedo } = useEnhancedRuleStore();\n  const [isHelpOpen, setIsHelpOpen] = useState(false);\n  \n  useKeyboardShortcuts([\n    {\n      key: 'z',\n      ctrl: true,\n      handler: () => canUndo() && undo(),\n      description: 'Undo last action'\n    },\n    {\n      key: 'y',\n      ctrl: true,\n      handler: () => canRedo() && redo(),\n      description: 'Redo last action'\n    },\n    {\n      key: 'z',\n      ctrl: true,\n      shift: true,\n      handler: () => canRedo() && redo(),\n      description: 'Redo last action (alternative)'\n    },\n    {\n      key: 's',\n      ctrl: true,\n      handler: (e) => {\n        e.preventDefault();\n        handleSave();\n      },\n      description: 'Save rule'\n    },\n    {\n      key: 'r',\n      ctrl: true,\n      handler: () => addNewConditionGroup(),\n      description: 'Add new rule group'\n    },\n    {\n      key: 'e',\n      ctrl: true,\n      shift: true,\n      handler: () => expandAll(),\n      description: 'Expand all groups'\n    },\n    {\n      key: 'c',\n      ctrl: true,\n      shift: true,\n      handler: () => collapseAll(),\n      description: 'Collapse all groups'\n    },\n    {\n      key: '?',\n      shift: true,\n      handler: () => setIsHelpOpen(true),\n      description: 'Show keyboard shortcuts help'\n    },\n    {\n      key: 'Escape',\n      handler: () => setIsHelpOpen(false),\n      description: 'Close dialogs'\n    }\n  ]);\n  \n  return (\n    <div>\n      <TreeRuleBuilder />\n      \n      {isHelpOpen && (\n        <KeyboardShortcutsHelp onClose={() => setIsHelpOpen(false)} />\n      )}\n    </div>\n  );\n}\n```\n\n**Platform Handling:**\n- **macOS**: `cmd` key automatically maps to Cmd key\n- **Windows/Linux**: `ctrl` key maps to Ctrl key\n- **Auto-detection**: Automatically detects platform and shows appropriate shortcuts\n- **Conflict Resolution**: Prevents conflicting shortcuts and provides warnings\n\n### useTheme\n\nTheme management with system preference detection.\n\n```typescript\ninterface ThemeAPI {\n  theme: 'light' | 'dark' | 'system';\n  resolvedTheme: 'light' | 'dark';\n  setTheme: (theme: 'light' | 'dark' | 'system') => void;\n  toggleTheme: () => void;\n  systemTheme: 'light' | 'dark';\n}\n```\n\n**Usage:**\n```tsx\nimport { useTheme } from '@usex/rule-engine-builder';\n\nfunction ThemedRuleBuilder() {\n  const { theme, resolvedTheme, setTheme, toggleTheme } = useTheme();\n  \n  return (\n    <div className={`min-h-screen ${resolvedTheme === 'dark' ? 'dark' : ''}`}>\n      <div className=\"bg-background text-foreground\">\n        <header className=\"flex justify-between items-center p-4\">\n          <h1>Rule Builder</h1>\n          <button onClick={toggleTheme}>\n            {resolvedTheme === 'dark' ? '☀️' : '🌙'}\n          </button>\n        </header>\n        \n        <TreeRuleBuilder theme={theme} />\n      </div>\n    </div>\n  );\n}\n```\n\n## Utility Hooks\n\n### useDebounce\n\nDebounce values and callbacks for performance optimization.\n\n```typescript\nfunction useDebounce<T>(value: T, delay: number): T;\nfunction useDebounce<T extends (...args: any[]) => any>(\n  callback: T, \n  delay: number\n): T;\n```\n\n**Usage:**\n```tsx\nimport { useDebounce } from '@usex/rule-engine-builder';\n\nfunction RuleBuilderWithDebouncing() {\n  const [rule, setRule] = useState(initialRule);\n  \n  // Debounce rule changes to avoid excessive API calls\n  const debouncedRule = useDebounce(rule, 500);\n  \n  // Debounce the save function\n  const debouncedSave = useDebounce((rule: RuleType) => {\n    saveRuleToServer(rule);\n  }, 1000);\n  \n  useEffect(() => {\n    if (debouncedRule) {\n      debouncedSave(debouncedRule);\n    }\n  }, [debouncedRule]);\n  \n  return (\n    <TreeRuleBuilder\n      onChange={setRule}\n      rule={rule}\n    />\n  );\n}\n```\n\n### useLocalStorage\n\nPersistent local storage with automatic serialization.\n\n```typescript\nfunction useLocalStorage<T>(\n  key: string,\n  defaultValue: T,\n  options?: {\n    serializer?: {\n      read: (value: string) => T;\n      write: (value: T) => string;\n    };\n    syncAcrossTabs?: boolean;\n  }\n): [T, (value: T | ((prev: T) => T)) => void, () => void];\n```\n\n**Usage:**\n```tsx\nimport { useLocalStorage } from '@usex/rule-engine-builder';\n\nfunction PersistentRuleBuilder() {\n  const [savedRule, setSavedRule, clearSavedRule] = useLocalStorage(\n    'rule-builder-draft',\n    { conditions: [], default: null },\n    { syncAcrossTabs: true }\n  );\n  \n  const [userPreferences, setUserPreferences] = useLocalStorage(\n    'rule-builder-preferences',\n    {\n      theme: 'system' as const,\n      showJsonViewer: true,\n      autoSave: true\n    }\n  );\n  \n  return (\n    <TreeRuleBuilder\n      initialRule={savedRule}\n      onChange={(rule) => {\n        if (userPreferences.autoSave) {\n          setSavedRule(rule);\n        }\n      }}\n      showJsonViewer={userPreferences.showJsonViewer}\n      theme={userPreferences.theme}\n    />\n  );\n}\n```\n\n### useEventListener\n\nType-safe event listener management.\n\n```typescript\nfunction useEventListener<T extends keyof WindowEventMap>(\n  eventType: T,\n  handler: (event: WindowEventMap[T]) => void,\n  options?: AddEventListenerOptions\n): void;\n\nfunction useEventListener<T extends keyof HTMLElementEventMap>(\n  eventType: T,\n  handler: (event: HTMLElementEventMap[T]) => void,\n  element: RefObject<HTMLElement>,\n  options?: AddEventListenerOptions\n): void;\n```\n\n**Usage:**\n```tsx\nimport { useEventListener } from '@usex/rule-engine-builder';\n\nfunction RuleBuilderWithEvents() {\n  const containerRef = useRef<HTMLDivElement>(null);\n  \n  // Global keyboard events\n  useEventListener('keydown', (event) => {\n    if (event.ctrlKey && event.key === 'k') {\n      event.preventDefault();\n      openCommandPalette();\n    }\n  });\n  \n  // Container-specific events\n  useEventListener('drop', (event) => {\n    event.preventDefault();\n    handleRuleDrop(event);\n  }, containerRef);\n  \n  return (\n    <div ref={containerRef}>\n      <TreeRuleBuilder />\n    </div>\n  );\n}\n```\n\n## Custom Hook Patterns\n\n### useAsyncRule\n\nHandle async rule operations with loading states.\n\n```typescript\nfunction useAsyncRule() {\n  const [rule, setRule] = useState<RuleType | null>(null);\n  const [isLoading, setIsLoading] = useState(false);\n  const [error, setError] = useState<Error | null>(null);\n  \n  const loadRule = useCallback(async (ruleId: string) => {\n    setIsLoading(true);\n    setError(null);\n    \n    try {\n      const loadedRule = await fetchRule(ruleId);\n      setRule(loadedRule);\n    } catch (err) {\n      setError(err as Error);\n    } finally {\n      setIsLoading(false);\n    }\n  }, []);\n  \n  const saveRule = useCallback(async (ruleToSave: RuleType) => {\n    setIsLoading(true);\n    setError(null);\n    \n    try {\n      const savedRule = await saveRuleToServer(ruleToSave);\n      setRule(savedRule);\n      return savedRule;\n    } catch (err) {\n      setError(err as Error);\n      throw err;\n    } finally {\n      setIsLoading(false);\n    }\n  }, []);\n  \n  return {\n    rule,\n    isLoading,\n    error,\n    loadRule,\n    saveRule,\n    setRule\n  };\n}\n```\n\n### useRuleValidation\n\nReal-time rule validation with detailed feedback.\n\n```typescript\nfunction useRuleValidation(rule: RuleType | null) {\n  const [validation, setValidation] = useState<ValidationResult | null>(null);\n  \n  useEffect(() => {\n    if (!rule) {\n      setValidation(null);\n      return;\n    }\n    \n    const validateAsync = async () => {\n      try {\n        const result = await RuleEngine.validate(rule);\n        setValidation(result);\n      } catch (error) {\n        setValidation({\n          isValid: false,\n          error: {\n            message: error.message,\n            path: '',\n            details: error\n          }\n        });\n      }\n    };\n    \n    validateAsync();\n  }, [rule]);\n  \n  return validation;\n}\n```\n\n### useRuleEvaluation\n\nReactive rule evaluation with caching.\n\n```typescript\nfunction useRuleEvaluation(rule: RuleType | null, data: any) {\n  const [result, setResult] = useState<EvaluationResult | null>(null);\n  const [isEvaluating, setIsEvaluating] = useState(false);\n  \n  const evaluate = useCallback(async () => {\n    if (!rule || !data) {\n      setResult(null);\n      return;\n    }\n    \n    setIsEvaluating(true);\n    \n    try {\n      const evaluationResult = await RuleEngine.evaluate(rule, data);\n      setResult(evaluationResult);\n    } catch (error) {\n      setResult({\n        value: rule.default || false,\n        isPassed: false,\n        message: `Evaluation error: ${error.message}`\n      });\n    } finally {\n      setIsEvaluating(false);\n    }\n  }, [rule, data]);\n  \n  useEffect(() => {\n    evaluate();\n  }, [evaluate]);\n  \n  return {\n    result,\n    isEvaluating,\n    evaluate\n  };\n}\n```\n\n### Hook Composition Example\n\n```tsx\nfunction AdvancedRuleBuilder({ ruleId }: { ruleId?: string }) {\n  // Core rule management\n  const { rule, isLoading, error, loadRule, saveRule } = useAsyncRule();\n  const { updateRule, undo, redo, canUndo, canRedo } = useEnhancedRuleStore();\n  \n  // Field discovery\n  const { fields, discover } = useFieldDiscovery();\n  \n  // Validation and evaluation\n  const validation = useRuleValidation(rule);\n  const { result: evaluationResult } = useRuleEvaluation(rule, sampleData);\n  \n  // UI state\n  const { theme, toggleTheme } = useTheme();\n  const [preferences, setPreferences] = useLocalStorage('preferences', {\n    autoSave: true,\n    showValidation: true\n  });\n  \n  // Keyboard shortcuts\n  useKeyboardShortcuts([\n    {\n      key: 's',\n      ctrl: true,\n      handler: () => rule && saveRule(rule),\n      description: 'Save rule'\n    },\n    {\n      key: 'z',\n      ctrl: true,\n      handler: () => canUndo() && undo(),\n      description: 'Undo'\n    }\n  ]);\n  \n  // Auto-save\n  const debouncedSave = useDebounce(saveRule, 2000);\n  \n  useEffect(() => {\n    if (rule && preferences.autoSave) {\n      debouncedSave(rule);\n    }\n  }, [rule, preferences.autoSave, debouncedSave]);\n  \n  // Load initial rule\n  useEffect(() => {\n    if (ruleId) {\n      loadRule(ruleId);\n    }\n  }, [ruleId, loadRule]);\n  \n  if (isLoading) return <div>Loading rule...</div>;\n  if (error) return <div>Error: {error.message}</div>;\n  \n  return (\n    <div className={theme === 'dark' ? 'dark' : ''}>\n      <div className=\"space-y-4\">\n        {/* Validation feedback */}\n        {preferences.showValidation && validation && !validation.isValid && (\n          <Alert variant=\"destructive\">\n            {validation.error?.message}\n          </Alert>\n        )}\n        \n        {/* Evaluation result */}\n        {evaluationResult && (\n          <div className={`p-2 rounded ${\n            evaluationResult.isPassed ? 'bg-green-100' : 'bg-red-100'\n          }`}>\n            Result: {JSON.stringify(evaluationResult.value)}\n          </div>\n        )}\n        \n        {/* Main rule builder */}\n        <TreeRuleBuilder\n          rule={rule}\n          fields={fields}\n          onChange={updateRule}\n          theme={theme}\n        />\n      </div>\n    </div>\n  );\n}\n```\n\n---\n\nFor more information, see the [main documentation](../README.md)."
  },
  {
    "path": "packages/builder/docs/integration.md",
    "content": "# Integration Guide\n\nComplete guide for integrating @usex/rule-engine-builder into your applications.\n\n## Table of Contents\n\n- [Framework Integration](#framework-integration)\n- [State Management Integration](#state-management-integration)\n- [Backend Integration](#backend-integration)\n- [Styling Integration](#styling-integration)\n- [Testing Integration](#testing-integration)\n- [Performance Optimization](#performance-optimization)\n\n## Framework Integration\n\n### React Integration\n\n#### Basic Setup\n\n```tsx\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\nimport '@usex/rule-engine-builder/styles';\n\nfunction App() {\n  return (\n    <div className=\"App\">\n      <TreeRuleBuilder\n        fields={fields}\n        onChange={handleRuleChange}\n      />\n    </div>\n  );\n}\n```\n\n#### With React Router\n\n```tsx\nimport { BrowserRouter as Router, Routes, Route } from 'react-router-dom';\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\n\nfunction RuleBuilderPage() {\n  const { ruleId } = useParams();\n  const [rule, setRule] = useState(null);\n  \n  useEffect(() => {\n    if (ruleId) {\n      loadRule(ruleId).then(setRule);\n    }\n  }, [ruleId]);\n  \n  return (\n    <TreeRuleBuilder\n      initialRule={rule}\n      onChange={handleRuleChange}\n    />\n  );\n}\n\nfunction App() {\n  return (\n    <Router>\n      <Routes>\n        <Route path=\"/rules/:ruleId\" element={<RuleBuilderPage />} />\n        <Route path=\"/rules/new\" element={<RuleBuilderPage />} />\n      </Routes>\n    </Router>\n  );\n}\n```\n\n#### With Context Providers\n\n```tsx\nimport { RuleBuilderProvider, useEnhancedRuleStore } from '@usex/rule-engine-builder';\n\nfunction RuleBuilderWithContext() {\n  return (\n    <RuleBuilderProvider>\n      <RuleBuilderContent />\n    </RuleBuilderProvider>\n  );\n}\n\nfunction RuleBuilderContent() {\n  const { rule, updateRule } = useEnhancedRuleStore();\n  \n  return (\n    <div className=\"grid grid-cols-2 gap-4\">\n      <TreeRuleBuilder onChange={updateRule} />\n      <RulePreview rule={rule} />\n    </div>\n  );\n}\n```\n\n### Next.js Integration\n\n#### App Router (Next.js 13+)\n\n```tsx\n// app/rules/page.tsx\n'use client';\n\nimport dynamic from 'next/dynamic';\nimport { useState } from 'react';\n\nconst TreeRuleBuilder = dynamic(\n  () => import('@usex/rule-engine-builder').then(mod => ({ default: mod.TreeRuleBuilder })),\n  { \n    ssr: false,\n    loading: () => <div>Loading rule builder...</div>\n  }\n);\n\nexport default function RulesPage() {\n  const [rule, setRule] = useState(null);\n  \n  return (\n    <div className=\"container mx-auto py-8\">\n      <h1 className=\"text-2xl font-bold mb-6\">Rule Builder</h1>\n      <TreeRuleBuilder\n        onChange={setRule}\n        className=\"min-h-[600px]\"\n      />\n    </div>\n  );\n}\n```\n\n#### API Routes Integration\n\n```tsx\n// app/api/rules/route.ts\nimport { NextRequest, NextResponse } from 'next/server';\nimport { RuleEngine } from '@usex/rule-engine';\n\nexport async function POST(request: NextRequest) {\n  const { rule, data } = await request.json();\n  \n  try {\n    // Validate rule\n    const validation = RuleEngine.validate(rule);\n    if (!validation.isValid) {\n      return NextResponse.json(\n        { error: validation.error.message },\n        { status: 400 }\n      );\n    }\n    \n    // Evaluate rule\n    const result = await RuleEngine.evaluate(rule, data);\n    \n    return NextResponse.json({ result });\n  } catch (error) {\n    return NextResponse.json(\n      { error: error.message },\n      { status: 500 }\n    );\n  }\n}\n```\n\n#### Server Components with Client Boundary\n\n```tsx\n// app/rules/[id]/page.tsx\nimport { RuleBuilderClient } from './rule-builder-client';\n\nasync function getRuleData(id: string) {\n  // Fetch rule data on server\n  const response = await fetch(`${process.env.API_URL}/rules/${id}`);\n  return response.json();\n}\n\nexport default async function RulePage({ params }: { params: { id: string } }) {\n  const ruleData = await getRuleData(params.id);\n  \n  return (\n    <div>\n      <h1>Edit Rule: {ruleData.name}</h1>\n      <RuleBuilderClient initialRule={ruleData.rule} />\n    </div>\n  );\n}\n```\n\n```tsx\n// app/rules/[id]/rule-builder-client.tsx\n'use client';\n\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\n\ninterface RuleBuilderClientProps {\n  initialRule: any;\n}\n\nexport function RuleBuilderClient({ initialRule }: RuleBuilderClientProps) {\n  return (\n    <TreeRuleBuilder\n      initialRule={initialRule}\n      onChange={handleRuleChange}\n    />\n  );\n}\n```\n\n### Vite Integration\n\n```tsx\n// vite.config.ts\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\nexport default defineConfig({\n  plugins: [react()],\n  optimizeDeps: {\n    include: ['@usex/rule-engine-builder']\n  },\n  css: {\n    postcss: './postcss.config.js'\n  }\n});\n```\n\n```tsx\n// src/App.tsx\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\nimport '@usex/rule-engine-builder/styles';\n\nfunction App() {\n  return (\n    <div className=\"min-h-screen bg-gray-50\">\n      <TreeRuleBuilder />\n    </div>\n  );\n}\n\nexport default App;\n```\n\n## State Management Integration\n\n### Redux Toolkit Integration\n\n```tsx\n// store/ruleSlice.ts\nimport { createSlice, PayloadAction } from '@reduxjs/toolkit';\n\ninterface RuleState {\n  currentRule: any;\n  rules: Record<string, any>;\n  isLoading: boolean;\n  error: string | null;\n}\n\nconst initialState: RuleState = {\n  currentRule: null,\n  rules: {},\n  isLoading: false,\n  error: null\n};\n\nconst ruleSlice = createSlice({\n  name: 'rules',\n  initialState,\n  reducers: {\n    setCurrentRule: (state, action: PayloadAction<any>) => {\n      state.currentRule = action.payload;\n    },\n    saveRule: (state, action: PayloadAction<{ id: string; rule: any }>) => {\n      const { id, rule } = action.payload;\n      state.rules[id] = rule;\n      state.currentRule = rule;\n    },\n    setLoading: (state, action: PayloadAction<boolean>) => {\n      state.isLoading = action.payload;\n    },\n    setError: (state, action: PayloadAction<string | null>) => {\n      state.error = action.payload;\n    }\n  }\n});\n\nexport const { setCurrentRule, saveRule, setLoading, setError } = ruleSlice.actions;\nexport default ruleSlice.reducer;\n```\n\n```tsx\n// components/RuleBuilderRedux.tsx\nimport { useSelector, useDispatch } from 'react-redux';\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\nimport { setCurrentRule } from '../store/ruleSlice';\n\nfunction RuleBuilderRedux() {\n  const dispatch = useDispatch();\n  const { currentRule, isLoading } = useSelector((state: RootState) => state.rules);\n  \n  const handleRuleChange = (rule: any) => {\n    dispatch(setCurrentRule(rule));\n  };\n  \n  if (isLoading) return <div>Loading...</div>;\n  \n  return (\n    <TreeRuleBuilder\n      rule={currentRule}\n      onChange={handleRuleChange}\n    />\n  );\n}\n```\n\n### Zustand Integration\n\n```tsx\n// store/ruleStore.ts\nimport { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\n\ninterface RuleStore {\n  rule: any;\n  history: any[];\n  setRule: (rule: any) => void;\n  addToHistory: (rule: any) => void;\n  clearHistory: () => void;\n}\n\nconst useRuleStore = create<RuleStore>()(\n  persist(\n    (set, get) => ({\n      rule: null,\n      history: [],\n      setRule: (rule) => {\n        const { addToHistory } = get();\n        addToHistory(rule);\n        set({ rule });\n      },\n      addToHistory: (rule) => {\n        set((state) => ({\n          history: [...state.history.slice(-9), rule] // Keep last 10\n        }));\n      },\n      clearHistory: () => set({ history: [] })\n    }),\n    {\n      name: 'rule-storage'\n    }\n  )\n);\n\nexport default useRuleStore;\n```\n\n### TanStack Query Integration\n\n```tsx\n// hooks/useRuleQueries.ts\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { RuleEngine } from '@usex/rule-engine';\n\nexport function useRule(ruleId: string) {\n  return useQuery({\n    queryKey: ['rule', ruleId],\n    queryFn: () => fetchRule(ruleId),\n    enabled: !!ruleId\n  });\n}\n\nexport function useSaveRule() {\n  const queryClient = useQueryClient();\n  \n  return useMutation({\n    mutationFn: saveRule,\n    onSuccess: (data, variables) => {\n      queryClient.setQueryData(['rule', variables.id], data);\n      queryClient.invalidateQueries({ queryKey: ['rules'] });\n    }\n  });\n}\n\nexport function useValidateRule() {\n  return useMutation({\n    mutationFn: (rule: any) => Promise.resolve(RuleEngine.validate(rule))\n  });\n}\n\nexport function useEvaluateRule() {\n  return useMutation({\n    mutationFn: ({ rule, data }: { rule: any; data: any }) =>\n      RuleEngine.evaluate(rule, data)\n  });\n}\n```\n\n```tsx\n// components/RuleBuilderWithQuery.tsx\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\nimport { useRule, useSaveRule, useValidateRule } from '../hooks/useRuleQueries';\n\nfunction RuleBuilderWithQuery({ ruleId }: { ruleId: string }) {\n  const { data: rule, isLoading } = useRule(ruleId);\n  const saveRuleMutation = useSaveRule();\n  const validateRuleMutation = useValidateRule();\n  \n  const handleSave = async (ruleToSave: any) => {\n    // Validate first\n    const validation = await validateRuleMutation.mutateAsync(ruleToSave);\n    if (!validation.isValid) {\n      throw new Error(validation.error.message);\n    }\n    \n    // Save if valid\n    await saveRuleMutation.mutateAsync({\n      id: ruleId,\n      rule: ruleToSave\n    });\n  };\n  \n  if (isLoading) return <div>Loading rule...</div>;\n  \n  return (\n    <TreeRuleBuilder\n      rule={rule}\n      onSave={handleSave}\n      onChange={debounce(handleSave, 1000)}\n    />\n  );\n}\n```\n\n## Backend Integration\n\n### Express.js API\n\n```typescript\n// routes/rules.ts\nimport express from 'express';\nimport { RuleEngine } from '@usex/rule-engine';\n\nconst router = express.Router();\n\n// Validate rule endpoint\nrouter.post('/validate', async (req, res) => {\n  try {\n    const { rule } = req.body;\n    const validation = RuleEngine.validate(rule);\n    res.json(validation);\n  } catch (error) {\n    res.status(500).json({ error: error.message });\n  }\n});\n\n// Evaluate rule endpoint\nrouter.post('/evaluate', async (req, res) => {\n  try {\n    const { rule, data } = req.body;\n    const result = await RuleEngine.evaluate(rule, data);\n    res.json(result);\n  } catch (error) {\n    res.status(500).json({ error: error.message });\n  }\n});\n\n// Save rule endpoint\nrouter.post('/rules', async (req, res) => {\n  try {\n    const { rule, name, description } = req.body;\n    \n    // Validate rule before saving\n    const validation = RuleEngine.validate(rule);\n    if (!validation.isValid) {\n      return res.status(400).json({ error: validation.error.message });\n    }\n    \n    // Save to database\n    const savedRule = await saveRuleToDatabase({\n      rule,\n      name,\n      description,\n      createdAt: new Date(),\n      userId: req.user.id\n    });\n    \n    res.json(savedRule);\n  } catch (error) {\n    res.status(500).json({ error: error.message });\n  }\n});\n\nexport default router;\n```\n\n### GraphQL Integration\n\n```typescript\n// schema/rule.ts\nimport { gql } from 'apollo-server-express';\nimport { RuleEngine } from '@usex/rule-engine';\n\nexport const typeDefs = gql`\n  type Rule {\n    id: ID!\n    name: String!\n    description: String\n    rule: JSON!\n    createdAt: String!\n    updatedAt: String!\n  }\n  \n  type ValidationResult {\n    isValid: Boolean!\n    error: String\n  }\n  \n  type EvaluationResult {\n    value: JSON!\n    isPassed: Boolean!\n    message: String\n  }\n  \n  type Query {\n    rule(id: ID!): Rule\n    rules: [Rule!]!\n  }\n  \n  type Mutation {\n    createRule(name: String!, description: String, rule: JSON!): Rule!\n    updateRule(id: ID!, name: String, description: String, rule: JSON): Rule!\n    validateRule(rule: JSON!): ValidationResult!\n    evaluateRule(rule: JSON!, data: JSON!): EvaluationResult!\n  }\n`;\n\nexport const resolvers = {\n  Query: {\n    rule: async (_, { id }, { dataSources }) => {\n      return await dataSources.ruleAPI.getRule(id);\n    },\n    rules: async (_, __, { dataSources }) => {\n      return await dataSources.ruleAPI.getRules();\n    }\n  },\n  \n  Mutation: {\n    createRule: async (_, { name, description, rule }, { dataSources }) => {\n      const validation = RuleEngine.validate(rule);\n      if (!validation.isValid) {\n        throw new Error(validation.error.message);\n      }\n      \n      return await dataSources.ruleAPI.createRule({\n        name,\n        description,\n        rule\n      });\n    },\n    \n    validateRule: async (_, { rule }) => {\n      return RuleEngine.validate(rule);\n    },\n    \n    evaluateRule: async (_, { rule, data }) => {\n      return await RuleEngine.evaluate(rule, data);\n    }\n  }\n};\n```\n\n### Database Integration\n\n```typescript\n// models/Rule.ts\nimport { Schema, model, Document } from 'mongoose';\n\ninterface IRule extends Document {\n  name: string;\n  description?: string;\n  rule: any;\n  version: number;\n  isActive: boolean;\n  tags: string[];\n  createdBy: string;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst ruleSchema = new Schema<IRule>({\n  name: { type: String, required: true },\n  description: { type: String },\n  rule: { type: Schema.Types.Mixed, required: true },\n  version: { type: Number, default: 1 },\n  isActive: { type: Boolean, default: true },\n  tags: [{ type: String }],\n  createdBy: { type: String, required: true },\n  createdAt: { type: Date, default: Date.now },\n  updatedAt: { type: Date, default: Date.now }\n});\n\n// Add validation middleware\nruleSchema.pre('save', function(next) {\n  const { RuleEngine } = require('@usex/rule-engine');\n  \n  const validation = RuleEngine.validate(this.rule);\n  if (!validation.isValid) {\n    return next(new Error(validation.error.message));\n  }\n  \n  this.updatedAt = new Date();\n  next();\n});\n\nexport const Rule = model<IRule>('Rule', ruleSchema);\n```\n\n## Styling Integration\n\n### Tailwind CSS Integration\n\n```tsx\n// tailwind.config.js\nmodule.exports = {\n  content: [\n    './src/**/*.{js,jsx,ts,tsx}',\n    './node_modules/@usex/rule-engine-builder/**/*.{js,jsx,ts,tsx}'\n  ],\n  theme: {\n    extend: {\n      colors: {\n        'rule-builder': {\n          primary: '#3b82f6',\n          secondary: '#6366f1',\n          success: '#10b981',\n          warning: '#f59e0b',\n          danger: '#ef4444'\n        }\n      }\n    }\n  },\n  plugins: []\n};\n```\n\n### Styled Components Integration\n\n```tsx\nimport styled, { ThemeProvider } from 'styled-components';\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\n\nconst theme = {\n  colors: {\n    primary: '#3b82f6',\n    background: '#ffffff',\n    border: '#e5e7eb'\n  },\n  spacing: {\n    sm: '0.5rem',\n    md: '1rem',\n    lg: '1.5rem'\n  }\n};\n\nconst StyledRuleBuilder = styled.div`\n  .rule-builder {\n    --primary-color: ${props => props.theme.colors.primary};\n    --background-color: ${props => props.theme.colors.background};\n    --border-color: ${props => props.theme.colors.border};\n  }\n`;\n\nfunction App() {\n  return (\n    <ThemeProvider theme={theme}>\n      <StyledRuleBuilder>\n        <TreeRuleBuilder className=\"rule-builder\" />\n      </StyledRuleBuilder>\n    </ThemeProvider>\n  );\n}\n```\n\n### CSS Modules Integration\n\n```css\n/* RuleBuilder.module.css */\n.container {\n  padding: 1rem;\n  background: var(--background-color);\n  border-radius: 0.5rem;\n}\n\n.header {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  margin-bottom: 1rem;\n}\n\n.content {\n  min-height: 400px;\n}\n\n:global(.rule-engine-builder) {\n  --primary-color: #3b82f6;\n  --secondary-color: #6366f1;\n}\n```\n\n```tsx\nimport styles from './RuleBuilder.module.css';\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\n\nfunction RuleBuilderComponent() {\n  return (\n    <div className={styles.container}>\n      <div className={styles.header}>\n        <h2>Rule Builder</h2>\n      </div>\n      <div className={styles.content}>\n        <TreeRuleBuilder />\n      </div>\n    </div>\n  );\n}\n```\n\n## Testing Integration\n\n### Jest Testing\n\n```tsx\n// __tests__/RuleBuilder.test.tsx\nimport { render, screen, fireEvent, waitFor } from '@testing-library/react';\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\n\n// Mock the heavy dependencies\njest.mock('@usex/rule-engine-builder', () => ({\n  TreeRuleBuilder: jest.fn(() => <div data-testid=\"rule-builder\">Rule Builder</div>)\n}));\n\ndescribe('RuleBuilder Integration', () => {\n  it('renders rule builder component', () => {\n    const handleChange = jest.fn();\n    \n    render(\n      <TreeRuleBuilder\n        onChange={handleChange}\n        fields={[]}\n      />\n    );\n    \n    expect(screen.getByTestId('rule-builder')).toBeInTheDocument();\n  });\n  \n  it('calls onChange when rule changes', async () => {\n    const handleChange = jest.fn();\n    const mockRule = { conditions: [], default: null };\n    \n    // Mock implementation that calls onChange\n    const MockTreeRuleBuilder = jest.fn(({ onChange }) => (\n      <button onClick={() => onChange(mockRule)}>\n        Update Rule\n      </button>\n    ));\n    \n    jest.mocked(TreeRuleBuilder).mockImplementation(MockTreeRuleBuilder);\n    \n    render(<TreeRuleBuilder onChange={handleChange} />);\n    \n    fireEvent.click(screen.getByText('Update Rule'));\n    \n    await waitFor(() => {\n      expect(handleChange).toHaveBeenCalledWith(mockRule);\n    });\n  });\n});\n```\n\n### Testing with Mock Service Worker\n\n```tsx\n// __tests__/setup.ts\nimport { setupServer } from 'msw/node';\nimport { rest } from 'msw';\n\nexport const server = setupServer(\n  rest.post('/api/rules/validate', (req, res, ctx) => {\n    return res(\n      ctx.json({\n        isValid: true,\n        error: null\n      })\n    );\n  }),\n  \n  rest.post('/api/rules/evaluate', (req, res, ctx) => {\n    return res(\n      ctx.json({\n        value: true,\n        isPassed: true,\n        message: null\n      })\n    );\n  })\n);\n\nbeforeAll(() => server.listen());\nafterEach(() => server.resetHandlers());\nafterAll(() => server.close());\n```\n\n### E2E Testing with Playwright\n\n```typescript\n// tests/rule-builder.spec.ts\nimport { test, expect } from '@playwright/test';\n\ntest.describe('Rule Builder', () => {\n  test('should create a new rule', async ({ page }) => {\n    await page.goto('/rules/new');\n    \n    // Wait for rule builder to load\n    await page.waitForSelector('[data-testid=\"rule-builder\"]');\n    \n    // Add a condition group\n    await page.click('[data-testid=\"add-condition-group\"]');\n    \n    // Select a field\n    await page.click('[data-testid=\"field-selector\"]');\n    await page.click('text=User Email');\n    \n    // Select an operator\n    await page.click('[data-testid=\"operator-selector\"]');\n    await page.click('text=equals');\n    \n    // Enter a value\n    await page.fill('[data-testid=\"value-input\"]', 'admin@example.com');\n    \n    // Save the rule\n    await page.click('[data-testid=\"save-button\"]');\n    \n    // Verify success message\n    await expect(page.locator('text=Rule saved successfully')).toBeVisible();\n  });\n  \n  test('should validate rule before saving', async ({ page }) => {\n    await page.goto('/rules/new');\n    \n    // Try to save empty rule\n    await page.click('[data-testid=\"save-button\"]');\n    \n    // Should show validation error\n    await expect(page.locator('text=Rule is invalid')).toBeVisible();\n  });\n});\n```\n\n## Performance Optimization\n\n### Code Splitting\n\n```tsx\nimport { lazy, Suspense } from 'react';\n\nconst TreeRuleBuilder = lazy(() =>\n  import('@usex/rule-engine-builder').then(module => ({\n    default: module.TreeRuleBuilder\n  }))\n);\n\nfunction App() {\n  return (\n    <Suspense fallback={<div>Loading rule builder...</div>}>\n      <TreeRuleBuilder />\n    </Suspense>\n  );\n}\n```\n\n### Memoization\n\n```tsx\nimport { memo, useMemo, useCallback } from 'react';\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\n\nconst MemoizedRuleBuilder = memo(TreeRuleBuilder);\n\nfunction OptimizedRuleBuilder({ data, onRuleChange }) {\n  const fields = useMemo(() => {\n    return discoverFields(data);\n  }, [data]);\n  \n  const handleRuleChange = useCallback((rule) => {\n    onRuleChange(rule);\n  }, [onRuleChange]);\n  \n  return (\n    <MemoizedRuleBuilder\n      fields={fields}\n      onChange={handleRuleChange}\n    />\n  );\n}\n```\n\n### Virtual Scrolling\n\n```tsx\nimport { FixedSizeList as List } from 'react-window';\nimport { TreeRuleBuilder } from '@usex/rule-engine-builder';\n\nfunction VirtualizedRuleList({ rules }) {\n  const renderRule = useCallback(({ index, style }) => (\n    <div style={style}>\n      <TreeRuleBuilder\n        key={rules[index].id}\n        rule={rules[index]}\n        compact={true}\n      />\n    </div>\n  ), [rules]);\n  \n  return (\n    <List\n      height={600}\n      itemCount={rules.length}\n      itemSize={200}\n      itemData={rules}\n    >\n      {renderRule}\n    </List>\n  );\n}\n```\n\n### Bundle Analysis\n\n```bash\n# Analyze bundle size\nnpm install --save-dev webpack-bundle-analyzer\n\n# Add script to package.json\n{\n  \"scripts\": {\n    \"analyze\": \"npx webpack-bundle-analyzer build/static/js/*.js\"\n  }\n}\n\n# Run analysis\nnpm run analyze\n```\n\n### Performance Monitoring\n\n```tsx\nimport { Profiler } from 'react';\n\nfunction onRenderCallback(id, phase, actualDuration) {\n  console.log('Component:', id, 'Phase:', phase, 'Duration:', actualDuration);\n}\n\nfunction App() {\n  return (\n    <Profiler id=\"RuleBuilder\" onRender={onRenderCallback}>\n      <TreeRuleBuilder />\n    </Profiler>\n  );\n}\n```\n\n---\n\nFor more integration examples and best practices, see the [main documentation](../README.md)."
  },
  {
    "path": "packages/builder/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\"/>\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/icon.svg\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"/>\n    <title>Rule Engine - Demo</title>\n\n    <!-- SEO Meta Tags -->\n    <meta name=\"description\"\n          content=\"Build complex business rules with an intuitive visual interface. Transform IF-THEN decisions into powerful JSON-based rule configurations with real-time evaluation.\"/>\n\n    <!-- Open Graph Meta Tags -->\n    <meta property=\"og:type\" content=\"website\"/>\n    <meta property=\"og:site_name\" content=\"Rule Engine Builder\"/>\n    <meta property=\"og:title\" content=\"Rule Engine Builder - Visual Business Logic Designer\"/>\n    <meta property=\"og:description\"\n          content=\"Build complex business rules with an intuitive visual interface. Transform IF-THEN decisions into powerful JSON-based rule configurations with real-time evaluation.\"/>\n    <meta property=\"og:url\" content=\"https://rule-engine.usestrict.dev\"/>\n    <meta property=\"og:image\" content=\"https://rule-engine.usestrict.dev/og-image.png\"/>\n    <meta property=\"og:image:width\" content=\"1200\"/>\n    <meta property=\"og:image:height\" content=\"630\"/>\n\n    <!-- Twitter Card Meta Tags -->\n    <meta property=\"twitter:card\" content=\"summary_large_image\"/>\n    <meta property=\"twitter:site\" content=\"@alimaster\"/>\n    <meta property=\"twitter:creator\" content=\"@alimaster\"/>\n    <meta property=\"twitter:title\" content=\"Rule Engine Builder - Visual Business Logic Designer\"/>\n    <meta property=\"twitter:description\"\n          content=\"Build complex business rules with an intuitive visual interface. Transform IF-THEN decisions into JSON-based configurations.\"/>\n    <meta property=\"twitter:image\" content=\"https://rule-engine.usestrict.dev/og-image.png\"/>\n\n    <!-- Additional Meta Tags -->\n    <meta name=\"author\" content=\"Ali Torki\"/>\n    <meta name=\"keywords\"\n          content=\"rule engine, business rules, visual programming, json rules, condition builder, logic designer, react component\"/>\n    <link rel=\"canonical\" href=\"https://rule-engine.usestrict.dev\"/>\n</head>\n<body>\n<div id=\"root\"></div>\n<script type=\"module\" src=\"/src/demo.tsx\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "packages/builder/package.json",
    "content": "{\n  \"name\": \"@usex/rule-engine-builder\",\n  \"type\": \"module\",\n  \"version\": \"0.0.3\",\n  \"private\": false,\n  \"description\": \"Visual rule construction toolkit for React applications. Drag, drop, and compose complex business logic without writing JSON. Transform IF-THEN decisions into intuitive visual flows with real-time evaluation, undo/redo history, and TypeScript-powered intelligence.\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/ali-master/rule-engine.git\",\n    \"directory\": \"packages/builder\"\n  },\n  \"keywords\": [\n    \"react-rule-builder\",\n    \"visual-rule-engine\",\n    \"business-logic-builder\",\n    \"no-code-rules\",\n    \"decision-tree-builder\",\n    \"if-then-else-builder\",\n    \"visual-programming\",\n    \"business-rules-ui\",\n    \"decision-engine-ui\",\n    \"visual-json-builder\",\n    \"rule-evaluation-ui\",\n    \"interactive-rule-editor\",\n    \"react\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.js\"\n    },\n    \"./styles\": {\n      \"import\": \"./dist/style.css\"\n    }\n  },\n  \"main\": \"./dist/index.js\",\n  \"module\": \"./dist/index.js\",\n  \"types\": \"./dist/index.d.ts\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"tsc -b && vite build\",\n    \"build:demo\": \"cd ../core && pnpm run build && cd ../builder && BUILD_MODE=demo vite build\",\n    \"preview\": \"vite preview\",\n    \"preview:demo\": \"BUILD_MODE=demo vite preview --outDir dist-demo\",\n    \"test:types\": \"tsc --noEmit\",\n    \"test:knip\": \"knip\",\n    \"test:knip:fix\": \"knip --fix\",\n    \"format:check\": \"prettier --check \\\"**/*.{ts,tsx,mdx}\\\"\",\n    \"format\": \"prettier --write \\\"**/*.{ts,tsx,mdx}\\\"\",\n    \"lint\": \"eslint \\\"src/**/*.{ts,tsx,js}\\\"\",\n    \"lint:fix\": \"pnpm run lint --fix\",\n    \"prepublishOnly\": \"pnpm lint\",\n    \"release\": \"cross-env CI=true pnpm run build\",\n    \"postrelease\": \"standard-version && pnpm publish --access public && git push --follow-tags origin master\",\n    \"release:beta\": \"pnpm run build\",\n    \"postrelease:beta\": \"standard-version --prerelease beta && pnpm publish --access public --tag beta && git push --follow-tags origin master\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^18.0.0 || ^19.0.0\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/core\": \"^6.3.1\",\n    \"@dnd-kit/sortable\": \"^10.0.0\",\n    \"@dnd-kit/utilities\": \"^3.2.2\",\n    \"@number-flow/react\": \"^0.5.10\",\n    \"@radix-ui/react-accordion\": \"^1.2.12\",\n    \"@radix-ui/react-alert-dialog\": \"^1.1.15\",\n    \"@radix-ui/react-checkbox\": \"^1.3.3\",\n    \"@radix-ui/react-collapsible\": \"^1.1.12\",\n    \"@radix-ui/react-dialog\": \"^1.1.15\",\n    \"@radix-ui/react-dropdown-menu\": \"^2.1.16\",\n    \"@radix-ui/react-hover-card\": \"^1.1.15\",\n    \"@radix-ui/react-label\": \"^2.1.7\",\n    \"@radix-ui/react-popover\": \"^1.1.15\",\n    \"@radix-ui/react-radio-group\": \"^1.3.8\",\n    \"@radix-ui/react-scroll-area\": \"^1.2.10\",\n    \"@radix-ui/react-select\": \"^2.2.6\",\n    \"@radix-ui/react-separator\": \"^1.1.7\",\n    \"@radix-ui/react-slider\": \"^1.3.6\",\n    \"@radix-ui/react-slot\": \"^1.2.3\",\n    \"@radix-ui/react-switch\": \"^1.2.6\",\n    \"@radix-ui/react-tabs\": \"^1.1.13\",\n    \"@radix-ui/react-toast\": \"^1.2.15\",\n    \"@radix-ui/react-toggle\": \"^1.1.10\",\n    \"@radix-ui/react-toggle-group\": \"^1.1.11\",\n    \"@radix-ui/react-tooltip\": \"^1.2.8\",\n    \"@usex/rule-engine\": \"workspace:*\",\n    \"@vercel/analytics\": \"^1.5.0\",\n    \"@vercel/speed-insights\": \"^1.2.0\",\n    \"class-variance-authority\": \"0.7.1\",\n    \"clsx\": \"2.1.1\",\n    \"cmdk\": \"^1.1.1\",\n    \"date-fns\": \"^4.1.0\",\n    \"diff\": \"^8.0.2\",\n    \"framer-motion\": \"^12.23.18\",\n    \"lucide-react\": \"0.544.0\",\n    \"react-day-picker\": \"^9.11.0\",\n    \"react-dnd\": \"^16.0.1\",\n    \"react-dnd-html5-backend\": \"^16.0.1\",\n    \"react-hook-form\": \"^7.63.0\",\n    \"sonner\": \"^2.0.7\",\n    \"tailwind-merge\": \"3.3.1\",\n    \"tw-animate-css\": \"1.3.8\",\n    \"vaul\": \"^1.1.2\",\n    \"zustand\": \"^5.0.8\"\n  },\n  \"devDependencies\": {\n    \"@tailwindcss/vite\": \"^4.1.13\",\n    \"@types/diff\": \"^8.0.0\",\n    \"@types/react\": \"^19.1.13\",\n    \"@types/react-dom\": \"^19.1.9\",\n    \"@vitejs/plugin-react-swc\": \"^4.1.0\",\n    \"autoprefixer\": \"^10.4.21\",\n    \"postcss\": \"^8.5.6\",\n    \"react\": \"^19.1.1\",\n    \"react-dom\": \"^19.1.1\",\n    \"tailwindcss\": \"^4.1.13\",\n    \"vite\": \"^7.1.7\",\n    \"vite-plugin-dts\": \"^4.5.4\",\n    \"vite-plugin-node-polyfills\": \"^0.24.0\"\n  }\n}\n"
  },
  {
    "path": "packages/builder/src/App.tsx",
    "content": "import { RuleEngine } from \"@usex/rule-engine\";\nimport { TestTube, PlayCircle, AlertCircle } from \"lucide-react\";\nimport React, { useState } from \"react\";\nimport { Toaster, toast } from \"sonner\";\nimport { ThemeProvider } from \"./components/theme-provider\";\nimport { ThemeToggle } from \"./components/theme-toggle\";\nimport { TreeRuleBuilder } from \"./components/TreeRuleBuilder\";\nimport { AlertDescription, Alert } from \"./components/ui/alert\";\nimport { Button } from \"./components/ui/button\";\nimport {\n  SheetTrigger,\n  SheetTitle,\n  SheetHeader,\n  SheetDescription,\n  SheetContent,\n  Sheet,\n} from \"./components/ui/sheet\";\nimport { Textarea } from \"./components/ui/textarea\";\nimport { useEnhancedRuleStore } from \"./stores/enhanced-rule-store\";\nimport \"./styles/globals.css\";\n\nconst sampleData = {\n  user: {\n    id: \"user-123\",\n    name: \"John Doe\",\n    email: \"john@example.com\",\n    age: 30,\n    isActive: true,\n    role: \"admin\",\n    tags: [\"premium\", \"verified\", \"beta\"],\n    profile: {\n      bio: \"Software developer\",\n      preferences: {\n        theme: \"dark\",\n        notifications: true,\n      },\n    },\n  },\n  product: {\n    id: \"prod-456\",\n    name: \"Premium Widget\",\n    price: 99.99,\n    inStock: true,\n    category: \"electronics\",\n    tags: [\"featured\", \"bestseller\"],\n  },\n  order: {\n    id: \"order-789\",\n    total: 299.97,\n    status: \"processing\",\n    itemCount: 3,\n    createdAt: new Date().toISOString(),\n  },\n};\n\nfunction AppContent() {\n  const { rule } = useEnhancedRuleStore();\n  const [testData, setTestData] = useState(JSON.stringify(sampleData, null, 2));\n  const [testResult, setTestResult] = useState<any>(null);\n  const [isTestRunning, setIsTestRunning] = useState(false);\n  const [isSheetOpen, setIsSheetOpen] = useState(false);\n\n  const handleTestRule = async () => {\n    setIsTestRunning(true);\n    setTestResult(null);\n\n    try {\n      const data = JSON.parse(testData);\n      const result = await RuleEngine.evaluate(rule, data);\n\n      // Handle single result or array of results\n      const isPassed = Array.isArray(result)\n        ? result.every((r) => r.isPassed)\n        : result.isPassed;\n\n      setTestResult({\n        success: true,\n        result,\n        passed: isPassed,\n      });\n\n      toast.success(\n        isPassed ? \"Rule evaluation passed!\" : \"Rule evaluation failed!\",\n      );\n    } catch (error: any) {\n      setTestResult({\n        success: false,\n        error: error.message,\n      });\n      toast.error(\"Error evaluating rule\");\n    } finally {\n      setIsTestRunning(false);\n    }\n  };\n\n  return (\n    <div className=\"min-h-screen bg-background\">\n      <Toaster position=\"top-center\" />\n\n      {/* Header */}\n      <header className=\"border-b bg-card\">\n        <div className=\"container mx-auto py-4 px-4\">\n          <div className=\"flex items-center justify-between\">\n            <div>\n              <h1 className=\"text-3xl font-bold\">Rule Engine Builder</h1>\n              <p className=\"text-muted-foreground mt-1\">\n                Build complex business rules with a tree structure\n              </p>\n            </div>\n\n            <div className=\"flex items-center gap-4\">\n              <ThemeToggle />\n\n              {/* Evaluate Button */}\n              <Sheet open={isSheetOpen} onOpenChange={setIsSheetOpen}>\n                <SheetTrigger asChild>\n                  <Button size=\"lg\">\n                    <TestTube className=\"h-5 w-5 mr-2\" />\n                    Evaluate Rule\n                  </Button>\n                </SheetTrigger>\n                <SheetContent className=\"w-[400px] sm:w-[540px]\">\n                  <SheetHeader>\n                    <SheetTitle>Evaluate Rule</SheetTitle>\n                    <SheetDescription>\n                      Test your rule against sample data\n                    </SheetDescription>\n                  </SheetHeader>\n\n                  <div className=\"mt-6 space-y-4\">\n                    <div className=\"space-y-2\">\n                      <label className=\"text-sm font-medium\">\n                        Test Data (JSON)\n                      </label>\n                      <Textarea\n                        value={testData}\n                        onChange={(e) => setTestData(e.target.value)}\n                        className=\"font-mono text-sm min-h-[300px]\"\n                        placeholder=\"Enter test data in JSON format\"\n                      />\n                    </div>\n\n                    <Button\n                      onClick={handleTestRule}\n                      disabled={isTestRunning}\n                      className=\"w-full\"\n                    >\n                      <PlayCircle className=\"h-4 w-4 mr-2\" />\n                      {isTestRunning ? \"Running...\" : \"Run Evaluation\"}\n                    </Button>\n\n                    {testResult && (\n                      <div className=\"space-y-3\">\n                        <Alert\n                          variant={\n                            testResult.success\n                              ? testResult.passed\n                                ? \"default\"\n                                : \"destructive\"\n                              : \"destructive\"\n                          }\n                        >\n                          <AlertCircle className=\"h-4 w-4\" />\n                          <AlertDescription>\n                            {testResult.success\n                              ? testResult.passed\n                                ? \"✅ Rule evaluation passed\"\n                                : \"❌ Rule evaluation failed\"\n                              : \"⚠️ Error during evaluation\"}\n                          </AlertDescription>\n                        </Alert>\n\n                        {testResult.success && (\n                          <div className=\"space-y-2\">\n                            <label className=\"text-sm font-medium\">\n                              Result\n                            </label>\n                            <pre className=\"text-xs bg-muted p-3 rounded-md overflow-x-auto\">\n                              {JSON.stringify(testResult.result, null, 2)}\n                            </pre>\n                          </div>\n                        )}\n\n                        {testResult.error && (\n                          <div className=\"space-y-2\">\n                            <label className=\"text-sm font-medium\">Error</label>\n                            <pre className=\"text-xs bg-destructive/10 text-destructive p-3 rounded-md\">\n                              {testResult.error}\n                            </pre>\n                          </div>\n                        )}\n                      </div>\n                    )}\n                  </div>\n                </SheetContent>\n              </Sheet>\n            </div>\n          </div>\n        </div>\n      </header>\n\n      {/* Main Content */}\n      <main className=\"container mx-auto py-8 px-4\">\n        <TreeRuleBuilder\n          sampleData={sampleData}\n          onChange={React.useCallback(\n            (rule: any) => console.log(\"Rule:\", rule),\n            [],\n          )}\n        />\n      </main>\n    </div>\n  );\n}\n\nexport function App() {\n  return (\n    <ThemeProvider defaultTheme=\"system\" storageKey=\"rule-builder-theme\">\n      <AppContent />\n    </ThemeProvider>\n  );\n}\n"
  },
  {
    "path": "packages/builder/src/components/AdvancedFieldInput.tsx",
    "content": "\"use client\";\n\nimport type { FieldConfig } from \"../types\";\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport {\n  Zap,\n  Type,\n  TrendingUp,\n  ToggleRight,\n  Sparkles,\n  Search,\n  List,\n  Hash,\n  FileJson,\n  Eye,\n  CornerDownLeft,\n  Command,\n  Code2,\n  Clock,\n  Calendar,\n  Braces,\n  ArrowRight,\n} from \"lucide-react\";\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { PopoverTrigger, PopoverContent, Popover } from \"./ui/popover\";\nimport { Separator } from \"./ui/separator\";\n\ninterface AdvancedFieldInputProps {\n  value: string;\n  onChange: (value: string) => void;\n  fields?: FieldConfig[];\n  sampleData?: Record<string, any>;\n  placeholder?: string;\n  disabled?: boolean;\n  className?: string;\n  allowJsonPath?: boolean;\n  showPreview?: boolean;\n  onFocus?: () => void;\n  onBlur?: () => void;\n}\n\ninterface FieldSuggestion {\n  path: string;\n  label: string;\n  type: string;\n  value?: any;\n  category: \"field\" | \"recent\" | \"popular\" | \"ai\" | \"path\";\n  matchScore?: number;\n  usageCount?: number;\n  lastUsed?: Date;\n  preview?: string;\n  description?: string;\n}\n\nconst typeIcons = {\n  string: Type,\n  number: Hash,\n  boolean: ToggleRight,\n  date: Calendar,\n  array: List,\n  object: Braces,\n  null: FileJson,\n  undefined: FileJson,\n};\n\nconst categoryIcons = {\n  field: FileJson,\n  recent: Clock,\n  popular: TrendingUp,\n  ai: Sparkles,\n  path: Code2,\n};\n\nconst RECENT_FIELDS_KEY = \"rule-builder-recent-fields\";\nconst POPULAR_FIELDS_KEY = \"rule-builder-popular-fields\";\nconst MAX_RECENT_FIELDS = 10;\nconst MAX_SUGGESTIONS = 50;\n\n// AI-powered field suggestions based on common patterns\nconst AI_FIELD_PATTERNS = [\n  {\n    pattern: /user|customer|person/i,\n    suggestions: [\"id\", \"name\", \"email\", \"age\", \"status\", \"role\", \"createdAt\"],\n  },\n  {\n    pattern: /product|item/i,\n    suggestions: [\"id\", \"name\", \"price\", \"category\", \"stock\", \"sku\", \"inStock\"],\n  },\n  {\n    pattern: /order|transaction/i,\n    suggestions: [\"id\", \"status\", \"total\", \"items\", \"date\", \"customerId\"],\n  },\n  {\n    pattern: /address|location/i,\n    suggestions: [\"street\", \"city\", \"state\", \"zip\", \"country\", \"coordinates\"],\n  },\n  {\n    pattern: /payment|billing/i,\n    suggestions: [\"method\", \"status\", \"amount\", \"currency\", \"cardLast4\"],\n  },\n  {\n    pattern: /settings|config/i,\n    suggestions: [\"theme\", \"notifications\", \"language\", \"timezone\"],\n  },\n];\n\n// Smart JSON path templates\nconst JSON_PATH_TEMPLATES = [\n  {\n    label: \"Array filter by property\",\n    path: \"$.[?(@.property == 'value')]\",\n    description: \"Filter array items by property value\",\n  },\n  {\n    label: \"Array map property\",\n    path: \"$.[*].property\",\n    description: \"Get property from all array items\",\n  },\n  {\n    label: \"Nested array access\",\n    path: \"$.parent[*].child[*].property\",\n    description: \"Access nested arrays\",\n  },\n  {\n    label: \"Conditional access\",\n    path: \"$..[?(@.active == true)].name\",\n    description: \"Get names of active items\",\n  },\n  {\n    label: \"Array slice\",\n    path: \"$.[0:5]\",\n    description: \"Get first 5 items from array\",\n  },\n  {\n    label: \"Recursive descent\",\n    path: \"$..property\",\n    description: \"Find property at any depth\",\n  },\n  {\n    label: \"Multiple properties\",\n    path: \"$.['prop1','prop2']\",\n    description: \"Select multiple properties\",\n  },\n];\n\nfunction getFieldType(value: any): string {\n  if (value === null) return \"null\";\n  if (value === undefined) return \"undefined\";\n  if (Array.isArray(value)) return \"array\";\n  if (value instanceof Date) return \"date\";\n  return typeof value;\n}\n\nfunction extractFieldsFromData(\n  data: any,\n  path = \"$\",\n  fields: FieldSuggestion[] = [],\n  depth = 0,\n  maxDepth = 5,\n): FieldSuggestion[] {\n  if (depth > maxDepth) return fields;\n\n  const type = getFieldType(data);\n\n  if (type === \"object\" && data !== null) {\n    Object.entries(data).forEach(([key, value]) => {\n      const fieldPath = `${path}.${key}`;\n      const fieldType = getFieldType(value);\n\n      fields.push({\n        path: fieldPath,\n        label: key,\n        type: fieldType,\n        value:\n          fieldType === \"object\" || fieldType === \"array\" ? undefined : value,\n        category: \"field\",\n        preview:\n          fieldType === \"string\" && value\n            ? (value as string).slice(0, 50)\n            : undefined,\n      });\n\n      if (fieldType === \"object\" || fieldType === \"array\") {\n        extractFieldsFromData(value, fieldPath, fields, depth + 1, maxDepth);\n      }\n    });\n  } else if (type === \"array\" && data?.length > 0) {\n    // Sample first item for array structure\n    const sample = data[0];\n    if (typeof sample === \"object\" && sample !== null) {\n      extractFieldsFromData(sample, `${path}[*]`, fields, depth + 1, maxDepth);\n    }\n  }\n\n  return fields;\n}\n\nfunction fuzzyMatch(input: string, target: string): number {\n  const inputLower = input.toLowerCase();\n  const targetLower = target.toLowerCase();\n\n  // Exact match\n  if (targetLower === inputLower) return 100;\n\n  // Starts with\n  if (targetLower.startsWith(inputLower)) return 90;\n\n  // Contains\n  if (targetLower.includes(inputLower)) return 70;\n\n  // Fuzzy character matching\n  let score = 0;\n  let j = 0;\n  for (let i = 0; i < inputLower.length; i++) {\n    const index = targetLower.indexOf(inputLower[i], j);\n    if (index === -1) continue;\n    score += (10 - (index - j)) * (i === 0 ? 2 : 1);\n    j = index + 1;\n  }\n\n  return Math.min(score, 60);\n}\n\nexport function AdvancedFieldInput({\n  value,\n  onChange,\n  fields = [],\n  sampleData,\n  placeholder = \"Select or type a field path...\",\n  disabled = false,\n  className,\n  allowJsonPath = true,\n  showPreview = true,\n  onFocus,\n  onBlur,\n}: AdvancedFieldInputProps) {\n  const [open, setOpen] = React.useState(false);\n  const [search, setSearch] = React.useState(\"\");\n  const [selectedCategory, setSelectedCategory] = React.useState<string | null>(\n    null,\n  );\n  const inputRef = React.useRef<HTMLInputElement>(null);\n  const [recentFields, setRecentFields] = React.useState<string[]>([]);\n  const [popularFields, setPopularFields] = React.useState<\n    Record<string, number>\n  >({});\n  const [previewValue, setPreviewValue] = React.useState<any>(null);\n  const [isComposing, setIsComposing] = React.useState(false);\n\n  // Load recent and popular fields from localStorage\n  React.useEffect(() => {\n    const stored = localStorage.getItem(RECENT_FIELDS_KEY);\n    if (stored) {\n      setRecentFields(JSON.parse(stored));\n    }\n\n    const storedPopular = localStorage.getItem(POPULAR_FIELDS_KEY);\n    if (storedPopular) {\n      setPopularFields(JSON.parse(storedPopular));\n    }\n  }, []);\n\n  // Extract available fields from sample data\n  const extractedFields = React.useMemo(() => {\n    if (!sampleData) return [];\n    return extractFieldsFromData(sampleData);\n  }, [sampleData]);\n\n  // Generate AI suggestions based on field names\n  const aiSuggestions = React.useMemo(() => {\n    const suggestions: FieldSuggestion[] = [];\n    const currentPath = value || search;\n\n    if (currentPath) {\n      const parts = currentPath.split(\".\");\n      const lastPart = parts[parts.length - 1];\n\n      AI_FIELD_PATTERNS.forEach(\n        ({ pattern, suggestions: fieldSuggestions }) => {\n          if (pattern.test(lastPart)) {\n            fieldSuggestions.forEach((suggestion) => {\n              const suggestedPath = [...parts.slice(0, -1), suggestion].join(\n                \".\",\n              );\n              suggestions.push({\n                path: suggestedPath.startsWith(\"$\")\n                  ? suggestedPath\n                  : `$.${suggestedPath}`,\n                label: suggestion,\n                type: \"unknown\",\n                category: \"ai\",\n                description: `Suggested field for ${lastPart}`,\n              });\n            });\n          }\n        },\n      );\n    }\n\n    return suggestions;\n  }, [value, search]);\n\n  // Combine all suggestions\n  const allSuggestions = React.useMemo(() => {\n    const suggestions: FieldSuggestion[] = [];\n\n    // Add defined fields\n    fields.forEach((field) => {\n      suggestions.push({\n        path: field.name,\n        label: field.label || field.name,\n        type: field.type || \"unknown\",\n        category: \"field\",\n        description: field.description,\n      });\n    });\n\n    // Add extracted fields\n    suggestions.push(...extractedFields);\n\n    // Add recent fields\n    recentFields.forEach((path) => {\n      if (!suggestions.find((s) => s.path === path)) {\n        suggestions.push({\n          path,\n          label: path.split(\".\").pop() || path,\n          type: \"unknown\",\n          category: \"recent\",\n        });\n      }\n    });\n\n    // Add popular fields\n    Object.entries(popularFields)\n      .sort(([, a], [, b]) => b - a)\n      .slice(0, 5)\n      .forEach(([path, count]) => {\n        const existing = suggestions.find((s) => s.path === path);\n        if (existing) {\n          existing.usageCount = count;\n        } else {\n          suggestions.push({\n            path,\n            label: path.split(\".\").pop() || path,\n            type: \"unknown\",\n            category: \"popular\",\n            usageCount: count,\n          });\n        }\n      });\n\n    // Add AI suggestions\n    suggestions.push(...aiSuggestions);\n\n    // Add JSON path templates if allowed\n    if (allowJsonPath && search.includes(\"$\")) {\n      JSON_PATH_TEMPLATES.forEach((template) => {\n        suggestions.push({\n          path: template.path,\n          label: template.label,\n          type: \"path\",\n          category: \"path\",\n          description: template.description,\n        });\n      });\n    }\n\n    return suggestions;\n  }, [\n    fields,\n    extractedFields,\n    recentFields,\n    popularFields,\n    aiSuggestions,\n    allowJsonPath,\n    search,\n  ]);\n\n  // Filter and score suggestions\n  const filteredSuggestions = React.useMemo(() => {\n    let filtered = allSuggestions;\n\n    // Filter by search\n    if (search) {\n      filtered = filtered\n        .map((suggestion) => ({\n          ...suggestion,\n          matchScore:\n            fuzzyMatch(search, suggestion.path) +\n            fuzzyMatch(search, suggestion.label),\n        }))\n        .filter((s) => s.matchScore && s.matchScore > 30)\n        .sort((a, b) => (b.matchScore || 0) - (a.matchScore || 0));\n    }\n\n    // Filter by category\n    if (selectedCategory) {\n      filtered = filtered.filter((s) => s.category === selectedCategory);\n    }\n\n    return filtered.slice(0, MAX_SUGGESTIONS);\n  }, [allSuggestions, search, selectedCategory]);\n\n  // Group suggestions by category\n  const groupedSuggestions = React.useMemo(() => {\n    const groups: Record<string, FieldSuggestion[]> = {};\n\n    filteredSuggestions.forEach((suggestion) => {\n      if (!groups[suggestion.category]) {\n        groups[suggestion.category] = [];\n      }\n      groups[suggestion.category].push(suggestion);\n    });\n\n    return groups;\n  }, [filteredSuggestions]);\n\n  // Calculate preview value\n  React.useEffect(() => {\n    if (!sampleData || !value) {\n      setPreviewValue(null);\n      return;\n    }\n\n    try {\n      const pathParts = value\n        .replace(\"$\", \"\")\n        .split(/[.[\\]]/)\n        .filter(Boolean);\n      let current = sampleData;\n\n      for (const part of pathParts) {\n        if (current === null || current === undefined) {\n          setPreviewValue(null);\n          return;\n        }\n\n        if (part === \"*\") {\n          setPreviewValue(Array.isArray(current) ? \"[Array items]\" : null);\n          return;\n        }\n\n        current = current[part];\n      }\n\n      setPreviewValue(current);\n    } catch {\n      setPreviewValue(null);\n    }\n  }, [value, sampleData]);\n\n  const handleSelect = (suggestion: FieldSuggestion) => {\n    onChange(suggestion.path);\n    setSearch(\"\");\n\n    // Update recent fields\n    const newRecent = [\n      suggestion.path,\n      ...recentFields.filter((f) => f !== suggestion.path),\n    ].slice(0, MAX_RECENT_FIELDS);\n    setRecentFields(newRecent);\n    localStorage.setItem(RECENT_FIELDS_KEY, JSON.stringify(newRecent));\n\n    // Update popular fields\n    const newPopular = { ...popularFields };\n    newPopular[suggestion.path] = (newPopular[suggestion.path] || 0) + 1;\n    setPopularFields(newPopular);\n    localStorage.setItem(POPULAR_FIELDS_KEY, JSON.stringify(newPopular));\n\n    // Delay closing to prevent flicker\n    setTimeout(() => {\n      setOpen(false);\n      inputRef.current?.focus();\n    }, 100);\n  };\n\n  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const newValue = e.target.value;\n    setSearch(newValue);\n\n    if (!isComposing) {\n      onChange(newValue);\n    }\n\n    if (!open && newValue) {\n      setOpen(true);\n    }\n  };\n\n  const handleInputFocus = () => {\n    // Small delay to prevent immediate close\n    setTimeout(() => {\n      setOpen(true);\n    }, 100);\n    onFocus?.();\n  };\n\n  const handleInputBlur = (e: React.FocusEvent) => {\n    // Don't close if clicking within the popover\n    const relatedTarget = e.relatedTarget as HTMLElement;\n    if (relatedTarget?.closest('[role=\"dialog\"]')) {\n      return;\n    }\n\n    // Small delay to allow click events to fire\n    setTimeout(() => {\n      setOpen(false);\n      onBlur?.();\n    }, 200);\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent) => {\n    if (e.key === \"Escape\") {\n      setOpen(false);\n    } else if (e.key === \"ArrowDown\" && !open) {\n      setOpen(true);\n    }\n  };\n\n  const fieldType =\n    value && previewValue !== null ? getFieldType(previewValue) : null;\n  const TypeIcon =\n    fieldType && fieldType in typeIcons\n      ? typeIcons[fieldType as keyof typeof typeIcons]\n      : value\n        ? FileJson\n        : Search;\n\n  return (\n    <Popover open={open} onOpenChange={setOpen}>\n      <PopoverTrigger asChild>\n        <div className=\"relative\">\n          <div className=\"absolute left-3 top-1/2 -translate-y-1/2 z-10\">\n            <TypeIcon\n              className={cn(\n                \"h-4 w-4\",\n                value && previewValue !== null\n                  ? \"text-primary\"\n                  : \"text-muted-foreground\",\n              )}\n            />\n          </div>\n          <input\n            ref={inputRef}\n            type=\"text\"\n            value={value}\n            onChange={handleInputChange}\n            onKeyDown={handleKeyDown}\n            onFocus={handleInputFocus}\n            onBlur={handleInputBlur}\n            onCompositionStart={() => setIsComposing(true)}\n            onCompositionEnd={() => {\n              setIsComposing(false);\n              onChange(search);\n            }}\n            placeholder={placeholder}\n            disabled={disabled}\n            className={cn(\n              \"flex h-10 w-full rounded-md border border-input bg-background px-10 py-2 text-sm ring-offset-background\",\n              \"file:border-0 file:bg-transparent file:text-sm file:font-medium\",\n              \"placeholder:text-muted-foreground\",\n              \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n              \"disabled:cursor-not-allowed disabled:opacity-50\",\n              className,\n            )}\n          />\n          {showPreview && previewValue !== null && (\n            <div className=\"absolute right-3 top-1/2 -translate-y-1/2 z-10\">\n              <Badge variant=\"secondary\" className=\"text-xs\">\n                <Eye className=\"h-3 w-3 mr-1\" />\n                {typeof previewValue === \"string\"\n                  ? previewValue.slice(0, 20)\n                  : getFieldType(previewValue)}\n              </Badge>\n            </div>\n          )}\n        </div>\n      </PopoverTrigger>\n\n      <PopoverContent\n        className=\"p-0 w-[600px]\"\n        align=\"start\"\n        sideOffset={4}\n        onOpenAutoFocus={(e) => e.preventDefault()}\n      >\n        <CommandPrimitive className=\"overflow-hidden rounded-md border shadow-md\">\n          <div className=\"flex items-center border-b px-3 py-2\">\n            <Search className=\"mr-2 h-4 w-4 text-muted-foreground\" />\n            <input\n              value={search}\n              onChange={(e) => setSearch(e.target.value)}\n              placeholder=\"Search fields...\"\n              className=\"flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground\"\n            />\n            <kbd className=\"ml-2 pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100\">\n              <span className=\"text-xs\">ESC</span>\n            </kbd>\n          </div>\n\n          {/* Category filters */}\n          <div className=\"flex items-center gap-1 border-b px-3 py-2\">\n            <Button\n              variant={selectedCategory === null ? \"secondary\" : \"ghost\"}\n              size=\"sm\"\n              className=\"h-7 text-xs\"\n              onClick={() => setSelectedCategory(null)}\n            >\n              All\n            </Button>\n            {Object.entries(categoryIcons).map(([category, Icon]) => (\n              <Button\n                key={category}\n                variant={selectedCategory === category ? \"secondary\" : \"ghost\"}\n                size=\"sm\"\n                className=\"h-7 text-xs\"\n                onClick={() => setSelectedCategory(category)}\n              >\n                <Icon className=\"h-3 w-3 mr-1\" />\n                {category.charAt(0).toUpperCase() + category.slice(1)}\n              </Button>\n            ))}\n          </div>\n\n          <div className=\"max-h-[400px] overflow-y-auto p-2\">\n            {Object.entries(groupedSuggestions).length === 0 ? (\n              <div className=\"py-8 text-center text-sm text-muted-foreground\">\n                No fields found\n              </div>\n            ) : (\n              Object.entries(groupedSuggestions).map(\n                ([category, suggestions]) => {\n                  const CategoryIcon =\n                    categoryIcons[category as keyof typeof categoryIcons] ||\n                    FileJson;\n\n                  return (\n                    <div key={category} className=\"mb-4 last:mb-0\">\n                      <div className=\"mb-2 flex items-center gap-2 px-2 text-xs font-medium text-muted-foreground\">\n                        <CategoryIcon className=\"h-3 w-3\" />\n                        {category.charAt(0).toUpperCase() + category.slice(1)}\n                      </div>\n\n                      {suggestions.map((suggestion, index) => {\n                        const FieldTypeIcon =\n                          typeIcons[\n                            suggestion.type as keyof typeof typeIcons\n                          ] || FileJson;\n\n                        return (\n                          <button\n                            key={`${suggestion.path}-${index}`}\n                            onClick={() => handleSelect(suggestion)}\n                            className={cn(\n                              \"relative flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none\",\n                              \"hover:bg-accent hover:text-accent-foreground\",\n                              \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n                              \"group\",\n                            )}\n                          >\n                            <FieldTypeIcon className=\"h-4 w-4 text-muted-foreground\" />\n\n                            <div className=\"flex-1 text-left\">\n                              <div className=\"flex items-center gap-2\">\n                                <span className=\"font-medium\">\n                                  {suggestion.label}\n                                </span>\n                                {suggestion.path !== suggestion.label && (\n                                  <code className=\"text-xs text-muted-foreground\">\n                                    {suggestion.path}\n                                  </code>\n                                )}\n                                {suggestion.usageCount &&\n                                  suggestion.usageCount > 1 && (\n                                    <Badge\n                                      variant=\"secondary\"\n                                      className=\"h-5 text-[10px]\"\n                                    >\n                                      {suggestion.usageCount}x\n                                    </Badge>\n                                  )}\n                              </div>\n                              {suggestion.description && (\n                                <div className=\"text-xs text-muted-foreground\">\n                                  {suggestion.description}\n                                </div>\n                              )}\n                              {suggestion.preview && (\n                                <div className=\"text-xs text-muted-foreground truncate\">\n                                  Preview: {suggestion.preview}\n                                </div>\n                              )}\n                            </div>\n\n                            {suggestion.category === \"ai\" && (\n                              <Zap className=\"h-3 w-3 text-yellow-500\" />\n                            )}\n\n                            <div className=\"opacity-0 group-hover:opacity-100 transition-opacity\">\n                              <kbd className=\"pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground\">\n                                <CornerDownLeft className=\"h-3 w-3\" />\n                              </kbd>\n                            </div>\n                          </button>\n                        );\n                      })}\n                    </div>\n                  );\n                },\n              )\n            )}\n          </div>\n\n          {allowJsonPath && (\n            <>\n              <Separator />\n              <div className=\"p-2\">\n                <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n                  <Command className=\"h-3 w-3\" />\n                  <span>Pro tip: Use $ for JSON path expressions</span>\n                  <ArrowRight className=\"h-3 w-3\" />\n                  <code className=\"text-xs bg-muted px-1 py-0.5 rounded\">{`$.users[?(@.age > 18)]`}</code>\n                </div>\n              </div>\n            </>\n          )}\n        </CommandPrimitive>\n      </PopoverContent>\n    </Popover>\n  );\n}\n"
  },
  {
    "path": "packages/builder/src/components/AnimatedNumber.tsx",
    "content": "import React from \"react\";\nimport NumberFlow, { useCanAnimate } from \"@number-flow/react\";\n\ninterface AnimatedNumberProps {\n  value: number;\n  format?: Intl.NumberFormatOptions;\n  className?: string;\n  animated?: boolean;\n}\n\nexport const AnimatedNumber: React.FC<AnimatedNumberProps> = ({\n  value,\n  format = {},\n  className,\n  animated = true,\n}) => {\n  const canAnimate = useCanAnimate();\n\n  if (!canAnimate || !animated) {\n    return (\n      <span className={className}>\n        {new Intl.NumberFormat(undefined, format).format(value)}\n      </span>\n    );\n  }\n\n  // Filter out unsupported notation types for NumberFlow\n  const numberFlowFormat = {\n    ...format,\n    notation:\n      format.notation === \"scientific\" || format.notation === \"engineering\"\n        ? \"standard\"\n        : format.notation,\n  };\n\n  return (\n    <NumberFlow\n      value={value}\n      format={numberFlowFormat}\n      animated\n      className={className}\n    />\n  );\n};\n\nAnimatedNumber.displayName = \"AnimatedNumber\";\n"
  },
  {
    "path": "packages/builder/src/components/ConditionGroup.tsx",
    "content": "import React from \"react\";\nimport { CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Button } from \"./ui/button\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectItem,\n  SelectContent,\n  Select,\n} from \"./ui/select\";\nimport { Label } from \"./ui/label\";\nimport { Trash2, Plus, ChevronRight, ChevronDown } from \"lucide-react\";\nimport { ConstraintEditor } from \"./ConstraintEditor\";\nimport { useRuleBuilder } from \"../stores/unified-rule-store\";\nimport { ConditionTypes } from \"@usex/rule-engine\";\nimport type { Constraint, ConditionType, Condition } from \"@usex/rule-engine\";\nimport type { ConditionGroupProps } from \"../types\";\nimport { cn } from \"../lib/utils\";\n\n// Extract default props to prevent infinite re-renders\nconst defaultFields: ConditionGroupProps[\"fields\"] = [];\nconst defaultOperators: ConditionGroupProps[\"operators\"] = [];\n\nconst isConstraint = (item: Constraint | Condition): item is Constraint => {\n  return \"field\" in item && \"operator\" in item;\n};\n\nexport const ConditionGroup: React.FC<ConditionGroupProps> = ({\n  condition,\n  path,\n  depth = 0,\n  readOnly = false,\n  fields = defaultFields,\n  operators = defaultOperators,\n  onRemove,\n}) => {\n  const {\n    addConstraint,\n    removeConstraint,\n    addCondition,\n    updateConstraint,\n    updateCondition,\n    removeCondition,\n  } = useRuleBuilder();\n  const [collapsed, setCollapsed] = React.useState(false);\n\n  const conditionType = React.useMemo(() => {\n    if (condition.or) return ConditionTypes.OR;\n    if (condition.and) return ConditionTypes.AND;\n    if (condition.none) return ConditionTypes.NONE;\n    return ConditionTypes.OR;\n  }, [condition]);\n\n  const items = React.useMemo(() => {\n    return condition[conditionType] || [];\n  }, [condition, conditionType]);\n\n  const handleConditionTypeChange = (newType: ConditionType) => {\n    if (newType === conditionType) return;\n\n    const newCondition: Condition = {\n      [newType]: items,\n      result: condition.result,\n    };\n\n    // Update condition directly through store\n    updateCondition(path, newCondition);\n  };\n\n  const handleAddConstraint = () => {\n    const newConstraint: Constraint = {\n      field: \"\",\n      operator: \"equals\" as any,\n      value: \"\",\n    };\n    // Add constraint to this condition group by appending the condition type to the path\n    const constraintPath = path ? `${path}.${conditionType}` : conditionType;\n    addConstraint(constraintPath, newConstraint);\n  };\n\n  const handleAddConditionGroup = () => {\n    // Add new condition group to this condition group by appending the condition type to the path\n    const parentPath = path ? `${path}.${conditionType}` : conditionType;\n    addCondition(parentPath, ConditionTypes.AND);\n  };\n\n  const handleUpdateItem = (index: number, item: Constraint | Condition) => {\n    if (isConstraint(item)) {\n      // Update constraint directly through store\n      const itemPath = path\n        ? `${path}.${conditionType}.${index}`\n        : `${conditionType}.${index}`;\n      updateConstraint(itemPath, item);\n    } else {\n      // Update condition directly through store\n      const itemPath = path\n        ? `${path}.${conditionType}.${index}`\n        : `${conditionType}.${index}`;\n      updateCondition(itemPath, item);\n    }\n  };\n\n  const handleRemoveItem = (index: number) => {\n    if (isConstraint(items[index])) {\n      // Remove constraint using store function\n      const itemPath = path\n        ? `${path}.${conditionType}.${index}`\n        : `${conditionType}.${index}`;\n      removeConstraint(itemPath);\n    } else {\n      // Remove condition using store function\n      const itemPath = path\n        ? `${path}.${conditionType}.${index}`\n        : `${conditionType}.${index}`;\n      removeCondition(itemPath);\n    }\n  };\n\n  const conditionTypeColor = {\n    [ConditionTypes.OR]:\n      \"text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-950/30 border-blue-200 dark:border-blue-800\",\n    [ConditionTypes.AND]:\n      \"text-green-600 dark:text-green-400 bg-green-50 dark:bg-green-950/30 border-green-200 dark:border-green-800\",\n    [ConditionTypes.NONE]:\n      \"text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-950/30 border-red-200 dark:border-red-800\",\n  };\n\n  return (\n    <Card\n      className={cn(\n        \"rounded-lg shadow-sm border-2\",\n        conditionTypeColor[conditionType],\n        depth > 0 && \"ml-8\",\n      )}\n    >\n      <CardHeader className=\"p-4\">\n        <div className=\"flex items-center justify-between\">\n          <div className=\"flex items-center gap-4\">\n            <Button\n              type=\"button\"\n              variant=\"ghost\"\n              size=\"sm\"\n              onClick={() => setCollapsed(!collapsed)}\n              className=\"p-0 h-auto\"\n            >\n              {collapsed ? (\n                <ChevronRight className=\"h-4 w-4\" />\n              ) : (\n                <ChevronDown className=\"h-4 w-4\" />\n              )}\n            </Button>\n\n            <div className=\"flex items-center gap-2\">\n              <Label className=\"text-gray-900 dark:text-gray-100 font-medium\">\n                Condition Type:\n              </Label>\n              <Select\n                value={conditionType}\n                onValueChange={handleConditionTypeChange}\n                disabled={readOnly}\n              >\n                <SelectTrigger className=\"w-[100px]\">\n                  <SelectValue />\n                </SelectTrigger>\n                <SelectContent>\n                  <SelectItem value={ConditionTypes.OR}>OR</SelectItem>\n                  <SelectItem value={ConditionTypes.AND}>AND</SelectItem>\n                  <SelectItem value={ConditionTypes.NONE}>NONE</SelectItem>\n                </SelectContent>\n              </Select>\n            </div>\n          </div>\n\n          <div className=\"flex items-center gap-2\">\n            {!readOnly && (\n              <>\n                <Button\n                  type=\"button\"\n                  variant=\"outline\"\n                  size=\"sm\"\n                  onClick={handleAddConstraint}\n                >\n                  <Plus className=\"h-4 w-4 mr-2\" />\n                  Add Rule\n                </Button>\n                <Button\n                  type=\"button\"\n                  variant=\"outline\"\n                  size=\"sm\"\n                  onClick={handleAddConditionGroup}\n                >\n                  <Plus className=\"h-4 w-4 mr-2\" />\n                  Add Group\n                </Button>\n              </>\n            )}\n            {!readOnly && onRemove && depth > 0 && (\n              <Button\n                type=\"button\"\n                variant=\"ghost\"\n                size=\"icon\"\n                onClick={onRemove}\n              >\n                <Trash2 className=\"h-4 w-4\" />\n              </Button>\n            )}\n          </div>\n        </div>\n      </CardHeader>\n\n      {!collapsed && (\n        <CardContent className=\"p-4 pt-0 space-y-4\">\n          {items.length === 0 ? (\n            <div className=\"text-center text-muted-foreground py-8\">\n              No rules in this group. Add a rule or condition group to get\n              started.\n            </div>\n          ) : (\n            items.map((item, index) => {\n              const itemPath = path\n                ? `${path}.${conditionType}.${index}`\n                : `${conditionType}.${index}`;\n\n              if (isConstraint(item)) {\n                return (\n                  <ConstraintEditor\n                    key={itemPath}\n                    constraint={item}\n                    path={itemPath}\n                    fields={fields}\n                    operators={operators}\n                    readOnly={readOnly}\n                    onUpdate={(constraint) =>\n                      updateConstraint(itemPath, constraint)\n                    }\n                    onRemove={() => handleRemoveItem(index)}\n                  />\n                );\n              } else {\n                return (\n                  <ConditionGroup\n                    key={itemPath}\n                    condition={item}\n                    path={itemPath}\n                    depth={depth + 1}\n                    fields={fields}\n                    operators={operators}\n                    readOnly={readOnly}\n                    onUpdate={(condition) => handleUpdateItem(index, condition)}\n                    onRemove={() => handleRemoveItem(index)}\n                  />\n                );\n              }\n            })\n          )}\n        </CardContent>\n      )}\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/ConstraintEditor.tsx",
    "content": "import React from \"react\";\nimport { CardContent, Card } from \"./ui/card\";\nimport { Button } from \"./ui/button\";\nimport { Input } from \"./ui/input\";\nimport { Label } from \"./ui/label\";\nimport { Trash2, AlertCircle } from \"lucide-react\";\nimport { FieldSelector } from \"./FieldSelector\";\nimport { OperatorSelector } from \"./OperatorSelector\";\nimport { ValueInput } from \"./ValueInput\";\nimport type { ConstraintEditorProps } from \"../types\";\nimport { cn } from \"../lib/utils\";\n\nexport const ConstraintEditor: React.FC<ConstraintEditorProps> = ({\n  constraint,\n  path,\n  fields,\n  operators,\n  readOnly = false,\n  onUpdate,\n  onRemove,\n}) => {\n  const handleFieldChange = (field: string) => {\n    if (onUpdate) {\n      onUpdate({ ...constraint, field });\n    }\n  };\n\n  const handleOperatorChange = (operator: any) => {\n    if (onUpdate) {\n      onUpdate({ ...constraint, operator });\n    }\n  };\n\n  const handleValueChange = (value: any) => {\n    if (onUpdate) {\n      onUpdate({ ...constraint, value });\n    }\n  };\n\n  const handleMessageChange = (message: string) => {\n    if (onUpdate) {\n      onUpdate({ ...constraint, message: message || undefined });\n    }\n  };\n\n  return (\n    <Card\n      className={cn(\n        \"relative rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800\",\n        readOnly && \"opacity-75\",\n      )}\n    >\n      <CardContent className=\"p-4 space-y-4\">\n        <div className=\"flex items-start gap-4\">\n          <div className=\"flex-1 space-y-4\">\n            <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n              <div className=\"space-y-2\">\n                <Label\n                  htmlFor={`${path}-field`}\n                  className=\"text-gray-900 dark:text-gray-100\"\n                >\n                  Field\n                </Label>\n                <FieldSelector\n                  value={constraint.field}\n                  onChange={handleFieldChange}\n                  fields={fields}\n                  disabled={readOnly}\n                />\n              </div>\n\n              <div className=\"space-y-2\">\n                <Label\n                  htmlFor={`${path}-operator`}\n                  className=\"text-gray-900 dark:text-gray-100\"\n                >\n                  Operator\n                </Label>\n                <OperatorSelector\n                  value={constraint.operator}\n                  onChange={handleOperatorChange}\n                  operators={operators}\n                  field={constraint.field}\n                  disabled={readOnly}\n                />\n              </div>\n\n              <div className=\"space-y-2\">\n                <Label\n                  htmlFor={`${path}-value`}\n                  className=\"text-gray-900 dark:text-gray-100\"\n                >\n                  Value\n                </Label>\n                <ValueInput\n                  value={constraint.value}\n                  onChange={handleValueChange}\n                  operator={constraint.operator}\n                  field={constraint.field}\n                  disabled={readOnly}\n                />\n              </div>\n            </div>\n\n            <div className=\"space-y-2\">\n              <Label\n                htmlFor={`${path}-message`}\n                className=\"flex items-center gap-2 text-gray-900 dark:text-gray-100\"\n              >\n                <AlertCircle className=\"h-4 w-4 text-gray-600 dark:text-gray-400\" />\n                Error Message (Optional)\n              </Label>\n              <Input\n                id={`${path}-message`}\n                value={constraint.message || \"\"}\n                onChange={(e) => handleMessageChange(e.target.value)}\n                placeholder=\"Custom error message\"\n                disabled={readOnly}\n              />\n            </div>\n          </div>\n\n          {!readOnly && onRemove && (\n            <Button\n              type=\"button\"\n              variant=\"ghost\"\n              size=\"icon\"\n              onClick={onRemove}\n              className=\"shrink-0\"\n            >\n              <Trash2 className=\"h-4 w-4\" />\n            </Button>\n          )}\n        </div>\n      </CardContent>\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/DiffViewer.tsx",
    "content": "import * as Diff from \"diff\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Plus,\n  Minus,\n  GitBranch,\n  FileJson,\n  Copy,\n  ChevronRight,\n  ChevronDown,\n  BarChart3,\n} from \"lucide-react\";\nimport React, { useState, useMemo } from \"react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"../lib/utils\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { ScrollArea } from \"./ui/scroll-area\";\nimport { Separator } from \"./ui/separator\";\nimport { TabsTrigger, TabsList, Tabs } from \"./ui/tabs\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"./ui/tooltip\";\n\ninterface DiffViewerProps {\n  oldValue: any;\n  newValue: any;\n  className?: string;\n  title?: string;\n  oldTitle?: string;\n  newTitle?: string;\n}\n\n// DiffStats Component\nconst DiffStatsComponent: React.FC<{ stats: DiffStats }> = ({ stats }) => {\n  const totalChanges =\n    (stats.addedProperties?.length || 0) +\n    (stats.removedProperties?.length || 0) +\n    (stats.modifiedProperties?.length || 0);\n\n  return (\n    <TooltipProvider>\n      <div className=\"flex items-center gap-2\">\n        {/* Basic Stats */}\n        <div className=\"flex items-center gap-1 text-sm\">\n          <Tooltip>\n            <TooltipTrigger asChild>\n              <Badge variant=\"secondary\" className=\"gap-1 cursor-help\">\n                <Plus className=\"h-3 w-3\" />\n                {stats.additions}\n              </Badge>\n            </TooltipTrigger>\n            <TooltipContent>\n              <p className=\"text-xs\">{stats.additions} lines added</p>\n            </TooltipContent>\n          </Tooltip>\n\n          <Tooltip>\n            <TooltipTrigger asChild>\n              <Badge variant=\"secondary\" className=\"gap-1 cursor-help\">\n                <Minus className=\"h-3 w-3\" />\n                {stats.deletions}\n              </Badge>\n            </TooltipTrigger>\n            <TooltipContent>\n              <p className=\"text-xs\">{stats.deletions} lines removed</p>\n            </TooltipContent>\n          </Tooltip>\n        </div>\n\n        <Separator orientation=\"vertical\" className=\"h-4\" />\n\n        {/* Property Changes */}\n        <Tooltip>\n          <TooltipTrigger asChild>\n            <Badge variant=\"outline\" className=\"gap-1 cursor-help\">\n              <GitBranch className=\"h-3 w-3\" />\n              {totalChanges} properties\n            </Badge>\n          </TooltipTrigger>\n          <TooltipContent className=\"max-w-xs\">\n            <div className=\"space-y-2\">\n              <p className=\"font-semibold text-xs\">Property Changes:</p>\n              {stats.addedProperties && stats.addedProperties.length > 0 && (\n                <div className=\"space-y-1\">\n                  <p className=\"text-xs text-green-600 dark:text-green-400\">\n                    Added ({stats.addedProperties.length}):\n                  </p>\n                  <ul className=\"text-xs space-y-0.5 ml-2\">\n                    {stats.addedProperties.slice(0, 5).map((prop, i) => (\n                      <li\n                        key={i}\n                        className=\"text-green-600 dark:text-green-400\"\n                      >\n                        + {prop}\n                      </li>\n                    ))}\n                    {stats.addedProperties.length > 5 && (\n                      <li className=\"text-muted-foreground\">\n                        ...and {stats.addedProperties.length - 5} more\n                      </li>\n                    )}\n                  </ul>\n                </div>\n              )}\n              {stats.removedProperties &&\n                stats.removedProperties.length > 0 && (\n                  <div className=\"space-y-1\">\n                    <p className=\"text-xs text-red-600 dark:text-red-400\">\n                      Removed ({stats.removedProperties.length}):\n                    </p>\n                    <ul className=\"text-xs space-y-0.5 ml-2\">\n                      {stats.removedProperties.slice(0, 5).map((prop, i) => (\n                        <li key={i} className=\"text-red-600 dark:text-red-400\">\n                          - {prop}\n                        </li>\n                      ))}\n                      {stats.removedProperties.length > 5 && (\n                        <li className=\"text-muted-foreground\">\n                          ...and {stats.removedProperties.length - 5} more\n                        </li>\n                      )}\n                    </ul>\n                  </div>\n                )}\n              {stats.modifiedProperties &&\n                stats.modifiedProperties.length > 0 && (\n                  <div className=\"space-y-1\">\n                    <p className=\"text-xs text-blue-600 dark:text-blue-400\">\n                      Modified ({stats.modifiedProperties.length}):\n                    </p>\n                    <ul className=\"text-xs space-y-0.5 ml-2\">\n                      {stats.modifiedProperties.slice(0, 5).map((prop, i) => (\n                        <li\n                          key={i}\n                          className=\"text-blue-600 dark:text-blue-400\"\n                        >\n                          ~ {prop}\n                        </li>\n                      ))}\n                      {stats.modifiedProperties.length > 5 && (\n                        <li className=\"text-muted-foreground\">\n                          ...and {stats.modifiedProperties.length - 5} more\n                        </li>\n                      )}\n                    </ul>\n                  </div>\n                )}\n            </div>\n          </TooltipContent>\n        </Tooltip>\n\n        {/* Summary */}\n        <Tooltip>\n          <TooltipTrigger asChild>\n            <Badge variant=\"outline\" className=\"gap-1 cursor-help text-xs\">\n              <BarChart3 className=\"h-3 w-3\" />\n              {Math.round(\n                (stats.changes / Math.max(stats.totalLines, 1)) * 100,\n              )}\n              % changed\n            </Badge>\n          </TooltipTrigger>\n          <TooltipContent>\n            <p className=\"text-xs\">\n              {stats.changes} of {stats.totalLines} lines changed\n            </p>\n          </TooltipContent>\n        </Tooltip>\n      </div>\n    </TooltipProvider>\n  );\n};\n\ninterface DiffLine {\n  type: \"added\" | \"removed\" | \"unchanged\" | \"context\";\n  content: string;\n  lineNumber: {\n    old?: number;\n    new?: number;\n  };\n  level?: number;\n}\n\ninterface DiffStats {\n  additions: number;\n  deletions: number;\n  changes: number;\n  totalLines: number;\n  addedProperties?: string[];\n  removedProperties?: string[];\n  modifiedProperties?: string[];\n}\n\nexport const DiffViewer: React.FC<DiffViewerProps> = ({\n  oldValue,\n  newValue,\n  className,\n  title = \"Diff Viewer\",\n  oldTitle = \"Original\",\n  newTitle = \"Modified\",\n}) => {\n  const [viewMode, setViewMode] = useState<\"split\" | \"unified\">(\"split\");\n  const [collapsedSections, setCollapsedSections] = useState<Set<string>>(\n    new Set(),\n  );\n\n  // Convert objects to formatted JSON strings\n  const oldJson = useMemo(() => JSON.stringify(oldValue, null, 2), [oldValue]);\n  const newJson = useMemo(() => JSON.stringify(newValue, null, 2), [newValue]);\n\n  // Helper function to get indentation level\n  const getIndentLevel = (line: string): number => {\n    const match = line.match(/^(\\s*)/);\n    return match ? match[1].length / 2 : 0;\n  };\n\n  // Calculate diff\n  const { diffLines, stats } = useMemo(() => {\n    const changes = Diff.diffLines(oldJson, newJson, {\n      ignoreWhitespace: false,\n    });\n\n    const lines: DiffLine[] = [];\n    let oldLineNum = 1;\n    let newLineNum = 1;\n    let additions = 0;\n    let deletions = 0;\n\n    changes.forEach((part) => {\n      const partLines = part.value.split(\"\\n\").filter((line) => line !== \"\");\n\n      if (part.added) {\n        additions += partLines.length;\n        partLines.forEach((line) => {\n          lines.push({\n            type: \"added\",\n            content: line,\n            lineNumber: { new: newLineNum++ },\n            level: getIndentLevel(line),\n          });\n        });\n      } else if (part.removed) {\n        deletions += partLines.length;\n        partLines.forEach((line) => {\n          lines.push({\n            type: \"removed\",\n            content: line,\n            lineNumber: { old: oldLineNum++ },\n            level: getIndentLevel(line),\n          });\n        });\n      } else {\n        // Context lines\n        partLines.forEach((line) => {\n          lines.push({\n            type: \"unchanged\",\n            content: line,\n            lineNumber: { old: oldLineNum++, new: newLineNum++ },\n            level: getIndentLevel(line),\n          });\n        });\n      }\n    });\n\n    // Calculate property-level changes\n    const oldObj = JSON.parse(oldJson);\n    const newObj = JSON.parse(newJson);\n\n    const analyzeProperties = (obj1: any, obj2: any, path = \"\") => {\n      const props = {\n        added: [] as string[],\n        removed: [] as string[],\n        modified: [] as string[],\n      };\n\n      const allKeys = new Set([\n        ...Object.keys(obj1 || {}),\n        ...Object.keys(obj2 || {}),\n      ]);\n\n      allKeys.forEach((key) => {\n        const fullPath = path ? `${path}.${key}` : key;\n\n        if (!(key in obj1)) {\n          props.added.push(fullPath);\n        } else if (!(key in obj2)) {\n          props.removed.push(fullPath);\n        } else if (JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])) {\n          props.modified.push(fullPath);\n\n          // Recursively analyze nested objects\n          if (\n            typeof obj1[key] === \"object\" &&\n            typeof obj2[key] === \"object\" &&\n            obj1[key] !== null &&\n            obj2[key] !== null &&\n            !Array.isArray(obj1[key]) &&\n            !Array.isArray(obj2[key])\n          ) {\n            const nested = analyzeProperties(obj1[key], obj2[key], fullPath);\n            props.added.push(...nested.added);\n            props.removed.push(...nested.removed);\n            props.modified = props.modified.filter((p) => p !== fullPath);\n            props.modified.push(...nested.modified);\n          }\n        }\n      });\n\n      return props;\n    };\n\n    const propertyChanges = analyzeProperties(oldObj, newObj);\n\n    return {\n      diffLines: lines,\n      stats: {\n        additions,\n        deletions,\n        changes: Math.min(additions, deletions),\n        totalLines: lines.length,\n        addedProperties: propertyChanges.added,\n        removedProperties: propertyChanges.removed,\n        modifiedProperties: propertyChanges.modified,\n      },\n    };\n  }, [oldJson, newJson]);\n\n  // Group consecutive unchanged lines for collapsing\n  const groupedLines = useMemo(() => {\n    const groups: Array<{\n      type: \"diff\" | \"context\";\n      lines: DiffLine[];\n      id: string;\n    }> = [];\n\n    let currentGroup: DiffLine[] = [];\n    let currentType: \"diff\" | \"context\" = \"context\";\n\n    diffLines.forEach((line) => {\n      const isDiff = line.type === \"added\" || line.type === \"removed\";\n      const groupType = isDiff ? \"diff\" : \"context\";\n\n      if (\n        groupType !== currentType ||\n        (currentType === \"context\" && currentGroup.length >= 10)\n      ) {\n        if (currentGroup.length > 0) {\n          groups.push({\n            type: currentType,\n            lines: currentGroup,\n            id: `group-${groups.length}`,\n          });\n        }\n        currentGroup = [line];\n        currentType = groupType;\n      } else {\n        currentGroup.push(line);\n      }\n    });\n\n    if (currentGroup.length > 0) {\n      groups.push({\n        type: currentType,\n        lines: currentGroup,\n        id: `group-${groups.length}`,\n      });\n    }\n\n    return groups;\n  }, [diffLines]);\n\n  const toggleSection = (id: string) => {\n    setCollapsedSections((prev) => {\n      const next = new Set(prev);\n      if (next.has(id)) {\n        next.delete(id);\n      } else {\n        next.add(id);\n      }\n      return next;\n    });\n  };\n\n  const copyToClipboard = async (text: string, label: string) => {\n    try {\n      await navigator.clipboard.writeText(text);\n      toast.success(`${label} copied to clipboard`);\n    } catch {\n      toast.error(\"Failed to copy to clipboard\");\n    }\n  };\n\n  const renderLineContent = (line: DiffLine) => {\n    const content = line.content;\n\n    // Syntax highlighting for JSON\n    const highlightedContent = content\n      .replace(\n        /(\"[\\w\\s-]+\")\\s*:/g,\n        '<span class=\"text-blue-600 dark:text-blue-400\">$1</span>:',\n      )\n      .replace(\n        /:\\s*(\".*?\")/g,\n        ': <span class=\"text-green-600 dark:text-green-400\">$1</span>',\n      )\n      .replace(\n        /:\\s*(\\d+)/g,\n        ': <span class=\"text-purple-600 dark:text-purple-400\">$1</span>',\n      )\n      .replace(\n        /:\\s*(true|false)/g,\n        ': <span class=\"text-orange-600 dark:text-orange-400\">$1</span>',\n      )\n      .replace(\n        /:\\s*(null)/g,\n        ': <span class=\"text-gray-500 dark:text-gray-400\">$1</span>',\n      );\n\n    return (\n      <span\n        dangerouslySetInnerHTML={{ __html: highlightedContent }}\n        className=\"font-mono text-sm\"\n      />\n    );\n  };\n\n  const renderUnifiedView = () => (\n    <ScrollArea className=\"h-full\">\n      <div className=\"p-4\">\n        {groupedLines.map((group) => {\n          const isCollapsed = collapsedSections.has(group.id);\n          const canCollapse =\n            group.type === \"context\" && group.lines.length > 3;\n\n          return (\n            <div key={group.id} className=\"mb-2\">\n              {canCollapse && (\n                <Button\n                  variant=\"ghost\"\n                  size=\"sm\"\n                  className=\"w-full justify-start h-6 px-2 text-xs text-muted-foreground hover:text-foreground\"\n                  onClick={() => toggleSection(group.id)}\n                >\n                  {isCollapsed ? (\n                    <ChevronRight className=\"h-3 w-3 mr-1\" />\n                  ) : (\n                    <ChevronDown className=\"h-3 w-3 mr-1\" />\n                  )}\n                  {isCollapsed\n                    ? `Show ${group.lines.length} unchanged lines`\n                    : \"Hide unchanged lines\"}\n                </Button>\n              )}\n\n              <AnimatePresence mode=\"wait\">\n                {!isCollapsed && (\n                  <motion.div\n                    initial={{ opacity: 0, height: 0 }}\n                    animate={{ opacity: 1, height: \"auto\" }}\n                    exit={{ opacity: 0, height: 0 }}\n                    transition={{ duration: 0.2 }}\n                  >\n                    {group.lines.map((line, idx) => (\n                      <div\n                        key={idx}\n                        className={cn(\n                          \"flex items-start border-l-4 pr-2\",\n                          line.type === \"added\" &&\n                            \"bg-green-50 dark:bg-green-950/30 border-green-500\",\n                          line.type === \"removed\" &&\n                            \"bg-red-50 dark:bg-red-950/30 border-red-500\",\n                          line.type === \"unchanged\" &&\n                            \"bg-transparent border-transparent\",\n                        )}\n                      >\n                        <div className=\"flex shrink-0 w-16 text-xs text-muted-foreground font-mono\">\n                          <span className=\"w-8 text-right pr-2\">\n                            {line.lineNumber.old || \"\"}\n                          </span>\n                          <span className=\"w-8 text-right pr-2\">\n                            {line.lineNumber.new || \"\"}\n                          </span>\n                        </div>\n                        <div className=\"flex items-center gap-1 shrink-0 w-6\">\n                          {line.type === \"added\" && (\n                            <Plus className=\"h-3 w-3 text-green-600\" />\n                          )}\n                          {line.type === \"removed\" && (\n                            <Minus className=\"h-3 w-3 text-red-600\" />\n                          )}\n                        </div>\n                        <div\n                          className=\"flex-1 overflow-x-auto\"\n                          style={{ paddingLeft: `${line.level || 0}ch` }}\n                        >\n                          {renderLineContent(line)}\n                        </div>\n                      </div>\n                    ))}\n                  </motion.div>\n                )}\n              </AnimatePresence>\n            </div>\n          );\n        })}\n      </div>\n    </ScrollArea>\n  );\n\n  const renderSplitView = () => {\n    // Separate lines for left and right panels\n    const leftLines: Array<DiffLine | null> = [];\n    const rightLines: Array<DiffLine | null> = [];\n\n    diffLines.forEach((line) => {\n      if (line.type === \"removed\") {\n        leftLines.push(line);\n        rightLines.push(null);\n      } else if (line.type === \"added\") {\n        leftLines.push(null);\n        rightLines.push(line);\n      } else {\n        leftLines.push(line);\n        rightLines.push(line);\n      }\n    });\n\n    return (\n      <div className=\"grid grid-cols-2 gap-2 h-full\">\n        {/* Left Panel */}\n        <Card className=\"flex flex-col overflow-hidden\">\n          <CardHeader className=\"py-2 px-4 border-b\">\n            <div className=\"flex items-center justify-between\">\n              <CardTitle className=\"text-sm font-medium\">{oldTitle}</CardTitle>\n              <Button\n                variant=\"ghost\"\n                size=\"sm\"\n                onClick={() => copyToClipboard(oldJson, oldTitle)}\n              >\n                <Copy className=\"h-3 w-3\" />\n              </Button>\n            </div>\n          </CardHeader>\n          <CardContent className=\"flex-1 p-0 overflow-hidden\">\n            <ScrollArea className=\"h-full\">\n              <div className=\"text-sm font-mono\">\n                {leftLines.map((line, idx) => (\n                  <div\n                    key={idx}\n                    className={cn(\n                      \"flex items-start pr-2 min-h-[24px]\",\n                      line?.type === \"removed\" &&\n                        \"bg-red-50 dark:bg-red-950/30\",\n                      !line && \"bg-gray-50 dark:bg-gray-950/30\",\n                    )}\n                  >\n                    <div className=\"shrink-0 w-10 text-xs text-muted-foreground text-right pr-2 py-1\">\n                      {line?.lineNumber.old || \"\"}\n                    </div>\n                    <div className=\"flex-1 py-1 overflow-x-auto\">\n                      {line ? renderLineContent(line) : \"\"}\n                    </div>\n                  </div>\n                ))}\n              </div>\n            </ScrollArea>\n          </CardContent>\n        </Card>\n\n        {/* Right Panel */}\n        <Card className=\"flex flex-col overflow-hidden\">\n          <CardHeader className=\"py-2 px-4 border-b\">\n            <div className=\"flex items-center justify-between\">\n              <CardTitle className=\"text-sm font-medium\">{newTitle}</CardTitle>\n              <Button\n                variant=\"ghost\"\n                size=\"sm\"\n                onClick={() => copyToClipboard(newJson, newTitle)}\n              >\n                <Copy className=\"h-3 w-3\" />\n              </Button>\n            </div>\n          </CardHeader>\n          <CardContent className=\"flex-1 p-0 overflow-hidden\">\n            <ScrollArea className=\"h-full\">\n              <div className=\"text-sm font-mono\">\n                {rightLines.map((line, idx) => (\n                  <div\n                    key={idx}\n                    className={cn(\n                      \"flex items-start pr-2 min-h-[24px]\",\n                      line?.type === \"added\" &&\n                        \"bg-green-50 dark:bg-green-950/30\",\n                      !line && \"bg-gray-50 dark:bg-gray-950/30\",\n                    )}\n                  >\n                    <div className=\"shrink-0 w-10 text-xs text-muted-foreground text-right pr-2 py-1\">\n                      {line?.lineNumber.new || \"\"}\n                    </div>\n                    <div className=\"flex-1 py-1 overflow-x-auto\">\n                      {line ? renderLineContent(line) : \"\"}\n                    </div>\n                  </div>\n                ))}\n              </div>\n            </ScrollArea>\n          </CardContent>\n        </Card>\n      </div>\n    );\n  };\n\n  return (\n    <Card className={cn(\"flex flex-col h-full\", className)}>\n      <CardHeader className=\"shrink-0\">\n        <div className=\"flex items-center justify-between\">\n          <div className=\"flex items-center gap-2\">\n            <FileJson className=\"h-5 w-5\" />\n            <CardTitle>{title}</CardTitle>\n          </div>\n          <div className=\"flex items-center gap-4\">\n            {/* Enhanced Stats */}\n            <DiffStatsComponent stats={stats} />\n\n            {/* View Mode Tabs */}\n            <Tabs value={viewMode} onValueChange={(v) => setViewMode(v as any)}>\n              <TabsList className=\"h-8\">\n                <TabsTrigger value=\"unified\" className=\"text-xs\">\n                  Unified\n                </TabsTrigger>\n                <TabsTrigger value=\"split\" className=\"text-xs\">\n                  Split\n                </TabsTrigger>\n              </TabsList>\n            </Tabs>\n          </div>\n        </div>\n      </CardHeader>\n\n      <CardContent className=\"flex-1 p-0 overflow-hidden\">\n        {viewMode === \"unified\" ? renderUnifiedView() : renderSplitView()}\n      </CardContent>\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/DraggableConditionGroup.tsx",
    "content": "import React from \"react\";\nimport { useSortable } from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { Card } from \"./ui/card\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport {\n  Trash2,\n  Plus,\n  GripVertical,\n  Copy,\n  ChevronRight,\n  ChevronDown,\n} from \"lucide-react\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectItem,\n  SelectContent,\n  Select,\n} from \"./ui/select\";\nimport type { ConditionType, Condition } from \"@usex/rule-engine\";\nimport { cn } from \"../lib/utils\";\n\ninterface DraggableConditionGroupProps {\n  id: string;\n  condition: Condition;\n  depth: number;\n  onUpdate: (condition: Condition) => void;\n  onRemove: () => void;\n  onDuplicate: () => void;\n  onAddConstraint: () => void;\n  onAddGroup: () => void;\n  children: React.ReactNode;\n  readOnly?: boolean;\n  labels?: {\n    or?: string;\n    and?: string;\n    none?: string;\n    addRule?: string;\n    addGroup?: string;\n  };\n  colors?: {\n    or?: string;\n    and?: string;\n    none?: string;\n  };\n  enableDragDrop?: boolean;\n}\n\nexport const DraggableConditionGroup: React.FC<\n  DraggableConditionGroupProps\n> = ({\n  id,\n  condition,\n  depth,\n  onUpdate,\n  onRemove,\n  onDuplicate,\n  onAddConstraint,\n  onAddGroup,\n  children,\n  readOnly = false,\n  labels = {},\n  colors = {},\n  enableDragDrop = true,\n}) => {\n  const [collapsed, setCollapsed] = React.useState(false);\n\n  const conditionConfig = React.useMemo(\n    () => ({\n      or: {\n        label: labels?.or || \"OR\",\n        color: colors?.or || \"hsl(var(--rule-or))\",\n        bg: \"hsl(var(--rule-or-bg))\",\n        description: \"At least one condition must be true\",\n      },\n      and: {\n        label: labels?.and || \"AND\",\n        color: colors?.and || \"hsl(var(--rule-and))\",\n        bg: \"hsl(var(--rule-and-bg))\",\n        description: \"All conditions must be true\",\n      },\n      none: {\n        label: labels?.none || \"NONE\",\n        color: colors?.none || \"hsl(var(--rule-none))\",\n        bg: \"hsl(var(--rule-none-bg))\",\n        description: \"No conditions should be true\",\n      },\n    }),\n    [labels, colors],\n  );\n\n  const {\n    attributes,\n    listeners,\n    setNodeRef,\n    transform,\n    transition,\n    isDragging,\n  } = useSortable({ id, disabled: readOnly || !enableDragDrop });\n\n  const style = {\n    transform: CSS.Transform.toString(transform),\n    transition,\n  };\n\n  const conditionType = (Object.keys(condition).find(\n    (key) => key === \"or\" || key === \"and\" || key === \"none\",\n  ) || \"or\") as ConditionType;\n\n  const config = conditionConfig[conditionType];\n  const items = condition[conditionType] || [];\n\n  const handleTypeChange = (newType: ConditionType) => {\n    if (newType === conditionType) return;\n\n    const newCondition: Condition = {\n      [newType]: items,\n      result: condition.result,\n    };\n\n    onUpdate(newCondition);\n  };\n\n  return (\n    <div\n      ref={setNodeRef}\n      style={style}\n      className={cn(\n        \"relative animate-fadeIn\",\n        isDragging && \"opacity-50\",\n        depth > 0 && \"ml-6\",\n      )}\n    >\n      <Card\n        className={cn(\n          \"border-2 transition-all duration-200\",\n          `hover:shadow-lg`,\n        )}\n        style={{\n          borderColor: config.color,\n          backgroundColor: config.bg,\n        }}\n      >\n        <div className=\"p-4\">\n          {/* Header */}\n          <div className=\"flex items-center justify-between mb-3\">\n            <div className=\"flex items-center gap-2\">\n              {!readOnly && enableDragDrop && (\n                <button\n                  className=\"cursor-grab active:cursor-grabbing text-muted-foreground hover:text-foreground\"\n                  {...attributes}\n                  {...listeners}\n                >\n                  <GripVertical className=\"h-5 w-5\" />\n                </button>\n              )}\n\n              <button\n                onClick={() => setCollapsed(!collapsed)}\n                className=\"p-1 hover:bg-background/50 rounded\"\n              >\n                {collapsed ? (\n                  <ChevronRight className=\"h-4 w-4\" />\n                ) : (\n                  <ChevronDown className=\"h-4 w-4\" />\n                )}\n              </button>\n\n              <Select\n                value={conditionType}\n                onValueChange={handleTypeChange}\n                disabled={readOnly}\n              >\n                <SelectTrigger className=\"w-[100px] h-8\">\n                  <SelectValue />\n                </SelectTrigger>\n                <SelectContent>\n                  {Object.entries(conditionConfig).map(([type, conf]) => (\n                    <SelectItem key={type} value={type}>\n                      <div className=\"flex items-center gap-2\">\n                        <Badge\n                          variant={type as any}\n                          className=\"w-12 justify-center\"\n                        >\n                          {conf.label}\n                        </Badge>\n                      </div>\n                    </SelectItem>\n                  ))}\n                </SelectContent>\n              </Select>\n\n              <span className=\"text-sm text-muted-foreground\">\n                {config.description}\n              </span>\n            </div>\n\n            <div className=\"flex items-center gap-1\">\n              {!readOnly && (\n                <>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    className=\"h-8 w-8\"\n                    onClick={onDuplicate}\n                  >\n                    <Copy className=\"h-4 w-4\" />\n                  </Button>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    className=\"h-8 w-8\"\n                    onClick={onAddConstraint}\n                  >\n                    <Plus className=\"h-4 w-4\" />\n                  </Button>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    className=\"h-8 w-8\"\n                    onClick={onAddGroup}\n                  >\n                    <Plus className=\"h-4 w-4\" />\n                    <Plus className=\"h-3 w-3 -ml-2\" />\n                  </Button>\n                  {depth > 0 && (\n                    <Button\n                      variant=\"ghost\"\n                      size=\"icon\"\n                      className=\"h-8 w-8 text-destructive hover:text-destructive\"\n                      onClick={onRemove}\n                    >\n                      <Trash2 className=\"h-4 w-4\" />\n                    </Button>\n                  )}\n                </>\n              )}\n            </div>\n          </div>\n\n          {/* Content */}\n          {!collapsed && (\n            <div className=\"space-y-3\">\n              {items.length === 0 ? (\n                <div className=\"text-center py-8 text-muted-foreground\">\n                  <p className=\"text-sm mb-3\">No conditions in this group</p>\n                  {!readOnly && (\n                    <div className=\"flex justify-center gap-2\">\n                      <Button\n                        variant=\"outline\"\n                        size=\"sm\"\n                        onClick={onAddConstraint}\n                      >\n                        <Plus className=\"h-4 w-4 mr-2\" />\n                        {labels?.addRule || \"Add Rule\"}\n                      </Button>\n                      <Button variant=\"outline\" size=\"sm\" onClick={onAddGroup}>\n                        <Plus className=\"h-4 w-4 mr-2\" />\n                        {labels?.addGroup || \"Add Group\"}\n                      </Button>\n                    </div>\n                  )}\n                </div>\n              ) : (\n                children\n              )}\n            </div>\n          )}\n        </div>\n      </Card>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/DynamicFieldSelector.tsx",
    "content": "import React, { useState, useMemo } from \"react\";\nimport {\n  CommandSeparator,\n  CommandList,\n  CommandItem,\n  CommandInput,\n  CommandGroup,\n  CommandEmpty,\n  Command,\n} from \"./ui/command\";\nimport { PopoverTrigger, PopoverContent, Popover } from \"./ui/popover\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { Input } from \"./ui/input\";\nimport {\n  Type,\n  ToggleRight,\n  Sparkles,\n  List,\n  Hash,\n  FileJson,\n  Code2,\n  ChevronsUpDown,\n  Calendar,\n  Braces,\n  AlertCircle,\n} from \"lucide-react\";\nimport { cn } from \"../lib/utils\";\nimport type { FieldConfig } from \"../types\";\nimport { useFieldDiscovery } from \"../hooks/use-field-discovery\";\n\ninterface DynamicFieldSelectorProps {\n  value: string;\n  onChange: (value: string) => void;\n  fields?: FieldConfig[];\n  sampleData?: Record<string, any>;\n  placeholder?: string;\n  disabled?: boolean;\n  className?: string;\n  allowCustom?: boolean;\n  showJsonPath?: boolean;\n}\n\nconst typeIcons = {\n  string: Type,\n  number: Hash,\n  boolean: ToggleRight,\n  date: Calendar,\n  array: List,\n  object: Braces,\n};\n\nexport const DynamicFieldSelector: React.FC<DynamicFieldSelectorProps> = ({\n  value,\n  onChange,\n  fields: providedFields = [],\n  sampleData,\n  placeholder = \"Select or enter field\",\n  disabled = false,\n  className,\n  allowCustom = true,\n  showJsonPath = true,\n}) => {\n  const [open, setOpen] = useState(false);\n  const [inputValue, setInputValue] = useState(value);\n  const [showCustomInput, setShowCustomInput] = useState(false);\n\n  const {\n    fields: discoveredFields,\n    getSuggestedFields,\n    validateJsonPath,\n  } = useFieldDiscovery({\n    sampleData,\n    customFields: providedFields,\n  });\n\n  const isJsonPath = value.startsWith(\"$\");\n  const validation = useMemo(() => {\n    if (isJsonPath) {\n      return validateJsonPath(value);\n    }\n    return { valid: true };\n  }, [value, isJsonPath, validateJsonPath]);\n\n  const allFields = useMemo(() => {\n    const fieldMap = new Map<string, FieldConfig>();\n\n    // Add discovered fields\n    discoveredFields.forEach((field) => {\n      fieldMap.set(field.name, field);\n    });\n\n    // Add provided fields (override if duplicate)\n    providedFields.forEach((field) => {\n      fieldMap.set(field.name, field);\n    });\n\n    return Array.from(fieldMap.values());\n  }, [discoveredFields, providedFields]);\n\n  const suggestions = useMemo(() => {\n    return getSuggestedFields(inputValue);\n  }, [inputValue, getSuggestedFields]);\n\n  const groupedFields = useMemo(() => {\n    const groups: Record<string, FieldConfig[]> = {};\n\n    suggestions.forEach((field) => {\n      const group = field.group || \"Fields\";\n      if (!groups[group]) {\n        groups[group] = [];\n      }\n      groups[group].push(field);\n    });\n\n    return groups;\n  }, [suggestions]);\n\n  const selectedField = allFields.find((f) => f.name === value);\n\n  const handleSelect = (fieldName: string) => {\n    onChange(fieldName);\n    setInputValue(fieldName);\n    setOpen(false);\n    setShowCustomInput(false);\n  };\n\n  const handleCustomSubmit = () => {\n    onChange(inputValue);\n    setOpen(false);\n    setShowCustomInput(false);\n  };\n\n  if (showCustomInput || (!selectedField && value && !allFields.length)) {\n    return (\n      <div className={cn(\"space-y-2\", className)}>\n        <div className=\"relative\">\n          <Input\n            value={inputValue}\n            onChange={(e) => {\n              setInputValue(e.target.value);\n              onChange(e.target.value);\n            }}\n            placeholder={placeholder}\n            disabled={disabled}\n            className={cn(\n              isJsonPath && \"font-mono text-xs pl-10\",\n              !validation.valid && \"border-destructive\",\n            )}\n          />\n          {isJsonPath && (\n            <FileJson className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n          )}\n        </div>\n        {!validation.valid && validation.error && (\n          <div className=\"flex items-center gap-2 text-xs text-destructive\">\n            <AlertCircle className=\"h-3 w-3\" />\n            {validation.error}\n          </div>\n        )}\n        {allFields.length > 0 && (\n          <Button\n            type=\"button\"\n            variant=\"ghost\"\n            size=\"sm\"\n            onClick={() => {\n              setShowCustomInput(false);\n              setInputValue(value);\n            }}\n            className=\"w-full\"\n          >\n            Select from list\n          </Button>\n        )}\n      </div>\n    );\n  }\n\n  return (\n    <Popover open={open} onOpenChange={setOpen}>\n      <PopoverTrigger asChild>\n        <Button\n          variant=\"outline\"\n          role=\"combobox\"\n          aria-expanded={open}\n          disabled={disabled}\n          className={cn(\"justify-between\", className)}\n        >\n          <div className=\"flex items-center gap-2 truncate\">\n            {selectedField ? (\n              <>\n                {React.createElement(\n                  typeIcons[selectedField.type as keyof typeof typeIcons] ||\n                    FileJson,\n                  {\n                    className: \"h-4 w-4 shrink-0\",\n                  },\n                )}\n                <span className=\"truncate\">\n                  {selectedField.label || selectedField.name}\n                </span>\n                {selectedField.jsonPath && (\n                  <Badge variant=\"outline\" className=\"ml-1\">\n                    JSONPath\n                  </Badge>\n                )}\n              </>\n            ) : value ? (\n              <>\n                <Code2 className=\"h-4 w-4 shrink-0\" />\n                <span className=\"font-mono text-xs truncate\">{value}</span>\n              </>\n            ) : (\n              <span className=\"text-muted-foreground\">{placeholder}</span>\n            )}\n          </div>\n          <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n        </Button>\n      </PopoverTrigger>\n      <PopoverContent className=\"w-[400px] p-0\" align=\"start\">\n        <Command>\n          <CommandInput\n            placeholder=\"Search fields...\"\n            value={inputValue}\n            onValueChange={setInputValue}\n          />\n          <CommandList>\n            <CommandEmpty>\n              <div className=\"py-6 text-center text-sm\">\n                <p className=\"text-muted-foreground mb-2\">No fields found</p>\n                {allowCustom && (\n                  <Button\n                    variant=\"outline\"\n                    size=\"sm\"\n                    onClick={() => {\n                      setShowCustomInput(true);\n                      setOpen(false);\n                    }}\n                  >\n                    <Sparkles className=\"h-4 w-4 mr-2\" />\n                    Enter custom field\n                  </Button>\n                )}\n              </div>\n            </CommandEmpty>\n\n            {Object.entries(groupedFields).map(([group, fields]) => (\n              <CommandGroup key={group} heading={group}>\n                {fields.map((field) => (\n                  <CommandItem\n                    key={field.name}\n                    value={field.name}\n                    onSelect={() => handleSelect(field.name)}\n                  >\n                    <div className=\"flex items-center gap-2 w-full\">\n                      {React.createElement(\n                        typeIcons[field.type as keyof typeof typeIcons] ||\n                          FileJson,\n                        {\n                          className: \"h-4 w-4 shrink-0 text-muted-foreground\",\n                        },\n                      )}\n                      <div className=\"flex-1 min-w-0\">\n                        <div className=\"flex items-center gap-2\">\n                          <span className=\"truncate\">\n                            {field.label || field.name}\n                          </span>\n                          {field.jsonPath && (\n                            <Badge variant=\"outline\" className=\"text-xs\">\n                              JSONPath\n                            </Badge>\n                          )}\n                        </div>\n                        {field.description && (\n                          <p className=\"text-xs text-muted-foreground truncate\">\n                            {field.description}\n                          </p>\n                        )}\n                      </div>\n                      <Badge variant=\"secondary\" className=\"ml-auto\">\n                        {field.type}\n                      </Badge>\n                    </div>\n                  </CommandItem>\n                ))}\n              </CommandGroup>\n            ))}\n\n            {allowCustom && inputValue && !selectedField && (\n              <>\n                <CommandSeparator />\n                <CommandGroup heading=\"Custom\">\n                  <CommandItem\n                    value={inputValue}\n                    onSelect={() => handleCustomSubmit()}\n                  >\n                    <Code2 className=\"h-4 w-4 mr-2\" />\n                    <span className=\"font-mono text-sm\">{inputValue}</span>\n                    <Badge variant=\"outline\" className=\"ml-auto\">\n                      Custom\n                    </Badge>\n                  </CommandItem>\n                </CommandGroup>\n              </>\n            )}\n\n            {showJsonPath && (\n              <>\n                <CommandSeparator />\n                <CommandGroup heading=\"JSONPath Examples\">\n                  <CommandItem\n                    value=\"$.field\"\n                    onSelect={() => handleSelect(\"$.field\")}\n                  >\n                    <FileJson className=\"h-4 w-4 mr-2\" />\n                    <div>\n                      <p className=\"font-mono text-sm\">$.field</p>\n                      <p className=\"text-xs text-muted-foreground\">\n                        Access a root-level field\n                      </p>\n                    </div>\n                  </CommandItem>\n                  <CommandItem\n                    value=\"$.parent.child\"\n                    onSelect={() => handleSelect(\"$.parent.child\")}\n                  >\n                    <FileJson className=\"h-4 w-4 mr-2\" />\n                    <div>\n                      <p className=\"font-mono text-sm\">$.parent.child</p>\n                      <p className=\"text-xs text-muted-foreground\">\n                        Access nested field\n                      </p>\n                    </div>\n                  </CommandItem>\n                  <CommandItem\n                    value=\"$.array[*]\"\n                    onSelect={() => handleSelect(\"$.array[*]\")}\n                  >\n                    <FileJson className=\"h-4 w-4 mr-2\" />\n                    <div>\n                      <p className=\"font-mono text-sm\">$.array[*]</p>\n                      <p className=\"text-xs text-muted-foreground\">\n                        All array elements\n                      </p>\n                    </div>\n                  </CommandItem>\n                  <CommandItem\n                    value=\"$..fieldName\"\n                    onSelect={() => handleSelect(\"$..fieldName\")}\n                  >\n                    <FileJson className=\"h-4 w-4 mr-2\" />\n                    <div>\n                      <p className=\"font-mono text-sm\">$..fieldName</p>\n                      <p className=\"text-xs text-muted-foreground\">\n                        Recursive search\n                      </p>\n                    </div>\n                  </CommandItem>\n                </CommandGroup>\n              </>\n            )}\n          </CommandList>\n        </Command>\n      </PopoverContent>\n    </Popover>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/EditableJsonViewer.tsx",
    "content": "import type { RuleType, EvaluationResult } from \"@usex/rule-engine\";\nimport { RuleEngine } from \"@usex/rule-engine\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Zap,\n  XCircle,\n  X,\n  Upload,\n  Save,\n  Play,\n  Minimize2,\n  Maximize2,\n  Info,\n  Edit2,\n  Download,\n  Copy,\n  CheckCircle2,\n  Check,\n  AlertCircle,\n  Activity,\n} from \"lucide-react\";\nimport React, { useState, useMemo, useEffect, useCallback } from \"react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"../lib/utils\";\nimport { JsonViewer } from \"./JsonVisualizer\";\nimport { AlertDescription, Alert } from \"./ui/alert\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Label } from \"./ui/label\";\nimport { Separator } from \"./ui/separator\";\nimport { Switch } from \"./ui/switch\";\nimport { Textarea } from \"./ui/textarea\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"./ui/tooltip\";\n\ninterface EditableJsonViewerProps {\n  rule: RuleType;\n  className?: string;\n  onUpdate?: (rule: RuleType) => void;\n  onImport?: (rule: RuleType) => void;\n  expanded?: boolean;\n  onExpandedChange?: (expanded: boolean) => void;\n  readOnly?: boolean;\n  sampleData?: any;\n  showEvaluator?: boolean;\n}\n\nexport const EditableJsonViewer: React.FC<EditableJsonViewerProps> = ({\n  rule,\n  className,\n  onUpdate,\n  onImport,\n  expanded = false,\n  onExpandedChange,\n  readOnly = false,\n  sampleData,\n  showEvaluator = true,\n}) => {\n  const [copied, setCopied] = useState(false);\n  const [isEditing, setIsEditing] = useState(false);\n  const [editedJson, setEditedJson] = useState(\"\");\n  const [error, setError] = useState<string | null>(null);\n  const fileInputRef = React.useRef<HTMLInputElement>(null);\n\n  // Evaluator state\n  const [isLiveMode, setIsLiveMode] = useState(false);\n  const [evaluationResult, setEvaluationResult] =\n    useState<EvaluationResult | null>(null);\n  const [isEvaluating, setIsEvaluating] = useState(false);\n\n  const jsonString = useMemo(() => {\n    return JSON.stringify(rule, null, 2);\n  }, [rule]);\n\n  const handleCopy = async () => {\n    try {\n      await navigator.clipboard.writeText(jsonString);\n      setCopied(true);\n      setTimeout(() => setCopied(false), 2000);\n      toast.success(\"JSON copied to clipboard\");\n    } catch (error) {\n      console.error(\"Failed to copy:\", error);\n      toast.error(\"Failed to copy JSON\");\n    }\n  };\n\n  const handleExport = () => {\n    const blob = new Blob([jsonString], { type: \"application/json\" });\n    const url = URL.createObjectURL(blob);\n    const a = document.createElement(\"a\");\n    a.href = url;\n    a.download = `rule-${Date.now()}.json`;\n    document.body.appendChild(a);\n    a.click();\n    document.body.removeChild(a);\n    URL.revokeObjectURL(url);\n    toast.success(\"Rule exported successfully\");\n  };\n\n  const handleImport = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const file = event.target.files?.[0];\n    if (!file || !onImport) return;\n\n    const reader = new FileReader();\n    reader.onload = (e) => {\n      try {\n        const content = e.target?.result as string;\n        const importedRule: RuleType = JSON.parse(content);\n        onImport(importedRule);\n        toast.success(\"Rule imported successfully\");\n      } catch (error) {\n        console.error(\"Failed to import rule:\", error);\n        toast.error(\"Failed to import rule: Invalid JSON\");\n      }\n    };\n    reader.readAsText(file);\n\n    if (fileInputRef.current) {\n      fileInputRef.current.value = \"\";\n    }\n  };\n\n  const handleSaveEdit = () => {\n    try {\n      const parsedRule = JSON.parse(editedJson) as RuleType;\n\n      // Basic validation\n      if (!parsedRule.conditions) {\n        throw new Error(\"Rule must have conditions\");\n      }\n\n      if (onUpdate) {\n        onUpdate(parsedRule);\n        setIsEditing(false);\n        setError(null);\n        toast.success(\"Rule updated successfully\");\n      }\n    } catch (err) {\n      const errorMessage = err instanceof Error ? err.message : \"Invalid JSON\";\n      setError(errorMessage);\n      toast.error(`Failed to update rule: ${errorMessage}`);\n    }\n  };\n\n  const handleStartEdit = () => {\n    setEditedJson(jsonString);\n    setIsEditing(true);\n  };\n\n  const handleCancelEdit = () => {\n    setIsEditing(false);\n    setEditedJson(\"\");\n    setError(null);\n  };\n\n  const lineCount = jsonString.split(\"\\n\").length;\n\n  // Evaluate rule function\n  const evaluateRule = useCallback(async () => {\n    if (!rule || !rule.conditions || !sampleData) {\n      return;\n    }\n\n    setIsEvaluating(true);\n\n    try {\n      const result = await RuleEngine.evaluate(rule, sampleData);\n      const evalResult = Array.isArray(result) ? result[0] : result;\n      setEvaluationResult(evalResult);\n    } catch {\n      setEvaluationResult(null);\n    } finally {\n      setIsEvaluating(false);\n    }\n  }, [rule, sampleData]);\n\n  // Live evaluation effect\n  useEffect(() => {\n    if (isLiveMode && showEvaluator) {\n      evaluateRule();\n    }\n  }, [isLiveMode, rule, sampleData, evaluateRule, showEvaluator]);\n\n  // Keyboard shortcuts\n  useEffect(() => {\n    if (!showEvaluator || !sampleData) return;\n\n    const handleKeyDown = (e: KeyboardEvent) => {\n      const isMac = navigator.userAgent.toUpperCase().includes(\"MAC\");\n      const ctrlOrCmd = isMac ? e.metaKey : e.ctrlKey;\n\n      // Toggle live mode: Ctrl/Cmd + E\n      if (ctrlOrCmd && e.key === \"e\" && !e.shiftKey) {\n        e.preventDefault();\n        setIsLiveMode((prev) => !prev);\n      }\n\n      // Run evaluation once: Ctrl/Cmd + Shift + E\n      if (ctrlOrCmd && e.shiftKey && e.key === \"E\") {\n        e.preventDefault();\n        if (!isLiveMode) {\n          evaluateRule();\n        }\n      }\n    };\n\n    window.addEventListener(\"keydown\", handleKeyDown);\n    return () => window.removeEventListener(\"keydown\", handleKeyDown);\n  }, [showEvaluator, sampleData, isLiveMode, evaluateRule]);\n\n  return (\n    <Card className={cn(\"overflow-hidden\", className)}>\n      <CardHeader className=\"space-y-0\">\n        {/* Evaluator Row */}\n        {showEvaluator && sampleData && (\n          <>\n            <div className=\"flex items-center justify-between py-2\">\n              <div className=\"flex items-center gap-3\">\n                <Activity className=\"h-4 w-4 text-muted-foreground\" />\n                <span className=\"text-sm font-medium\">Rule Evaluation</span>\n                <TooltipProvider>\n                  <Tooltip>\n                    <TooltipTrigger asChild>\n                      <Info className=\"h-3 w-3 text-muted-foreground cursor-help\" />\n                    </TooltipTrigger>\n                    <TooltipContent side=\"bottom\" className=\"max-w-xs\">\n                      <div className=\"space-y-2\">\n                        <p className=\"text-sm\">\n                          Evaluate your rule against sample data in real-time\n                        </p>\n                        <div className=\"space-y-1 text-xs\">\n                          <div className=\"flex items-center gap-2\">\n                            <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-xs font-mono\">\n                              Ctrl/Cmd + E\n                            </kbd>\n                            <span>Toggle live mode</span>\n                          </div>\n                          <div className=\"flex items-center gap-2\">\n                            <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-xs font-mono\">\n                              Ctrl/Cmd + Shift + E\n                            </kbd>\n                            <span>Run once</span>\n                          </div>\n                        </div>\n                      </div>\n                    </TooltipContent>\n                  </Tooltip>\n                </TooltipProvider>\n                {isEvaluating && (\n                  <motion.div\n                    animate={{ rotate: 360 }}\n                    transition={{\n                      duration: 1,\n                      repeat: Infinity,\n                      ease: \"linear\",\n                    }}\n                  >\n                    <Zap className=\"h-3 w-3 text-yellow-500\" />\n                  </motion.div>\n                )}\n                {evaluationResult && (\n                  <AnimatePresence mode=\"wait\">\n                    <motion.div\n                      key={evaluationResult.isPassed ? \"pass\" : \"fail\"}\n                      initial={{ scale: 0 }}\n                      animate={{ scale: 1 }}\n                      exit={{ scale: 0 }}\n                      transition={{\n                        type: \"spring\",\n                        stiffness: 500,\n                        damping: 30,\n                      }}\n                      className={cn(\n                        \"flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium\",\n                        evaluationResult.isPassed\n                          ? \"bg-green-500/20 text-green-600\"\n                          : \"bg-red-500/20 text-red-600\",\n                      )}\n                    >\n                      {evaluationResult.isPassed ? (\n                        <>\n                          <CheckCircle2 className=\"h-3 w-3\" />\n                          <span>Pass</span>\n                        </>\n                      ) : (\n                        <>\n                          <XCircle className=\"h-3 w-3\" />\n                          <span>Fail</span>\n                        </>\n                      )}\n                    </motion.div>\n                  </AnimatePresence>\n                )}\n              </div>\n              <div className=\"flex items-center gap-3\">\n                <div className=\"flex items-center gap-2\">\n                  <Label\n                    htmlFor=\"live-eval\"\n                    className=\"text-xs cursor-pointer select-none\"\n                  >\n                    Live\n                  </Label>\n                  <Switch\n                    id=\"live-eval\"\n                    checked={isLiveMode}\n                    onCheckedChange={setIsLiveMode}\n                    className=\"data-[state=checked]:bg-primary\"\n                  />\n                </div>\n                {!isLiveMode && (\n                  <Button\n                    variant=\"ghost\"\n                    size=\"sm\"\n                    onClick={evaluateRule}\n                    disabled={isEvaluating}\n                    className=\"h-7 px-2 text-xs\"\n                  >\n                    <Play className=\"h-3 w-3 mr-1\" />\n                    Evaluate\n                  </Button>\n                )}\n              </div>\n            </div>\n            <Separator className=\"mb-3\" />\n          </>\n        )}\n\n        {/* Original Header */}\n        <div className=\"flex flex-row items-center justify-between pb-3\">\n          <div className=\"flex items-center gap-2\">\n            <CardTitle className=\"text-base font-medium\">Rule JSON</CardTitle>\n            <Badge variant=\"secondary\" className=\"text-xs\">\n              {lineCount} lines\n            </Badge>\n            {isEditing && (\n              <Badge variant=\"destructive\" className=\"text-xs\">\n                Editing\n              </Badge>\n            )}\n          </div>\n          <div className=\"flex items-center gap-1\">\n            {!isEditing && (\n              <>\n                {onImport && (\n                  <>\n                    <input\n                      ref={fileInputRef}\n                      type=\"file\"\n                      accept=\".json,application/json\"\n                      onChange={handleImport}\n                      className=\"hidden\"\n                    />\n                    <Button\n                      variant=\"ghost\"\n                      size=\"icon\"\n                      className=\"h-8 w-8\"\n                      onClick={() => fileInputRef.current?.click()}\n                      title=\"Import JSON\"\n                    >\n                      <Upload className=\"h-4 w-4\" />\n                    </Button>\n                  </>\n                )}\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"h-8 w-8\"\n                  onClick={handleExport}\n                  title=\"Export JSON\"\n                >\n                  <Download className=\"h-4 w-4\" />\n                </Button>\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"h-8 w-8\"\n                  onClick={handleCopy}\n                  title=\"Copy JSON\"\n                >\n                  {copied ? (\n                    <Check className=\"h-4 w-4 text-green-600\" />\n                  ) : (\n                    <Copy className=\"h-4 w-4\" />\n                  )}\n                </Button>\n                {!readOnly && onUpdate && (\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    className=\"h-8 w-8\"\n                    onClick={handleStartEdit}\n                    title=\"Edit JSON\"\n                  >\n                    <Edit2 className=\"h-4 w-4\" />\n                  </Button>\n                )}\n              </>\n            )}\n            {isEditing && (\n              <>\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"h-8 w-8 text-green-600 hover:text-green-700\"\n                  onClick={handleSaveEdit}\n                  title=\"Save changes\"\n                >\n                  <Save className=\"h-4 w-4\" />\n                </Button>\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"h-8 w-8 text-destructive hover:text-destructive\"\n                  onClick={handleCancelEdit}\n                  title=\"Cancel editing\"\n                >\n                  <X className=\"h-4 w-4\" />\n                </Button>\n              </>\n            )}\n            {onExpandedChange && (\n              <Button\n                variant=\"ghost\"\n                size=\"icon\"\n                className=\"h-8 w-8\"\n                onClick={() => onExpandedChange(!expanded)}\n                title={expanded ? \"Minimize\" : \"Maximize\"}\n              >\n                {expanded ? (\n                  <Minimize2 className=\"h-4 w-4\" />\n                ) : (\n                  <Maximize2 className=\"h-4 w-4\" />\n                )}\n              </Button>\n            )}\n          </div>\n        </div>\n      </CardHeader>\n      <CardContent className=\"p-0\">\n        {error && (\n          <Alert variant=\"destructive\" className=\"mx-4 mb-2\">\n            <AlertCircle className=\"h-4 w-4\" />\n            <AlertDescription>{error}</AlertDescription>\n          </Alert>\n        )}\n        <div\n          className={cn(\n            \"overflow-auto\",\n            expanded ? \"max-h-[80vh]\" : \"max-h-[400px]\",\n          )}\n        >\n          {isEditing ? (\n            <Textarea\n              value={editedJson}\n              onChange={(e) => {\n                setEditedJson(e.target.value);\n                setError(null);\n              }}\n              className=\"min-h-[400px] font-mono text-sm border-0 focus-visible:ring-0 resize-none rounded-none\"\n              style={{ minHeight: expanded ? \"70vh\" : \"400px\" }}\n              placeholder=\"Enter valid JSON...\"\n            />\n          ) : (\n            <div className=\"p-4\">\n              <JsonViewer\n                data={rule}\n                rootName=\"rule\"\n                defaultExpanded={true}\n                className=\"max-w-full\"\n                highlightLogicalOperators={true}\n              />\n            </div>\n          )}\n        </div>\n      </CardContent>\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/FieldSelector.tsx",
    "content": "import React from \"react\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectLabel,\n  SelectItem,\n  SelectGroup,\n  SelectContent,\n  Select,\n} from \"./ui/select\";\nimport { Input } from \"./ui/input\";\nimport type { FieldSelectorProps } from \"../types\";\nimport { cn } from \"../lib/utils\";\n\n// Extract default props to prevent infinite re-renders\nconst defaultFields: FieldSelectorProps[\"fields\"] = [];\n\nexport const FieldSelector: React.FC<FieldSelectorProps> = ({\n  value,\n  onChange,\n  fields = defaultFields,\n  placeholder = \"Select or enter field\",\n  disabled = false,\n  className,\n}) => {\n  const [isCustom, setIsCustom] = React.useState(false);\n  const [customValue, setCustomValue] = React.useState(value || \"\");\n\n  React.useEffect(() => {\n    if (value && !fields.some((f) => f.name === value)) {\n      setIsCustom(true);\n      setCustomValue(value);\n    }\n  }, [value, fields]);\n\n  const groupedFields = React.useMemo(() => {\n    const groups: Record<string, typeof fields> = {};\n    const ungrouped: typeof fields = [];\n\n    fields.forEach((field) => {\n      if (field.group) {\n        if (!groups[field.group]) {\n          groups[field.group] = [];\n        }\n        groups[field.group].push(field);\n      } else {\n        ungrouped.push(field);\n      }\n    });\n\n    return { groups, ungrouped };\n  }, [fields]);\n\n  if (isCustom || fields.length === 0) {\n    return (\n      <div className={cn(\"relative\", className)}>\n        <Input\n          value={customValue}\n          onChange={(e) => {\n            setCustomValue(e.target.value);\n            onChange(e.target.value);\n          }}\n          placeholder={placeholder}\n          disabled={disabled}\n          className={cn(\n            value?.startsWith(\"$.\") && \"font-mono text-xs\",\n            className,\n          )}\n        />\n        {fields.length > 0 && (\n          <button\n            type=\"button\"\n            onClick={() => {\n              setIsCustom(false);\n              setCustomValue(\"\");\n              onChange(\"\");\n            }}\n            className=\"absolute right-2 top-1/2 -translate-y-1/2 text-xs text-muted-foreground hover:text-foreground\"\n            disabled={disabled}\n          >\n            Select from list\n          </button>\n        )}\n      </div>\n    );\n  }\n\n  return (\n    <div className={cn(\"relative\", className)}>\n      <Select value={value} onValueChange={onChange} disabled={disabled}>\n        <SelectTrigger className={className}>\n          <SelectValue placeholder={placeholder} />\n        </SelectTrigger>\n        <SelectContent>\n          {groupedFields.ungrouped.length > 0 && (\n            <SelectGroup>\n              {groupedFields.ungrouped.map((field) => (\n                <SelectItem key={field.name} value={field.name}>\n                  <div className=\"flex flex-col\">\n                    <span>{field.label || field.name}</span>\n                    {field.description && (\n                      <span className=\"text-xs text-muted-foreground\">\n                        {field.description}\n                      </span>\n                    )}\n                  </div>\n                </SelectItem>\n              ))}\n            </SelectGroup>\n          )}\n\n          {Object.entries(groupedFields.groups).map(([group, groupFields]) => (\n            <SelectGroup key={group}>\n              <SelectLabel>{group}</SelectLabel>\n              {groupFields.map((field) => (\n                <SelectItem key={field.name} value={field.name}>\n                  <div className=\"flex flex-col\">\n                    <span>{field.label || field.name}</span>\n                    {field.description && (\n                      <span className=\"text-xs text-muted-foreground\">\n                        {field.description}\n                      </span>\n                    )}\n                  </div>\n                </SelectItem>\n              ))}\n            </SelectGroup>\n          ))}\n\n          <SelectGroup>\n            <SelectLabel>Advanced</SelectLabel>\n            <SelectItem value=\"__custom__\" onSelect={() => setIsCustom(true)}>\n              <div className=\"flex flex-col\">\n                <span>Custom Field (JSONPath)</span>\n                <span className=\"text-xs text-muted-foreground\">\n                  Enter a custom field path or JSONPath expression\n                </span>\n              </div>\n            </SelectItem>\n          </SelectGroup>\n        </SelectContent>\n      </Select>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/HistoryViewer.tsx",
    "content": "import type { HistoryEntry } from \"../stores/unified-rule-store\";\nimport { formatDistanceToNow, format } from \"date-fns\";\nimport {\n  XCircle,\n  Search,\n  RotateCcw,\n  GitBranch,\n  Eye,\n  Clock,\n  CheckCircle,\n  ArrowRight,\n  ArrowLeft,\n} from \"lucide-react\";\nimport React, { useState, useMemo } from \"react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"../lib/utils\";\nimport { useUnifiedRuleStore } from \"../stores/unified-rule-store\";\nimport { DiffViewer } from \"./DiffViewer\";\nimport { JsonViewer } from \"./JsonVisualizer\";\nimport { ResizablePanel } from \"./ResizablePanel\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Input } from \"./ui/input\";\nimport { ScrollArea } from \"./ui/scroll-area\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectItem,\n  SelectContent,\n  Select,\n} from \"./ui/select\";\nimport { TabsTrigger, TabsList, TabsContent, Tabs } from \"./ui/tabs\";\nimport {\n  ZoomDialogTitle,\n  ZoomDialogHeader,\n  ZoomDialogDescription,\n  ZoomDialogContent,\n  ZoomDialog,\n} from \"./ui/zoom-dialog\";\n\ninterface HistoryViewerProps {\n  className?: string;\n}\n\nexport const HistoryViewer: React.FC<HistoryViewerProps> = ({ className }) => {\n  const [open, setOpen] = useState(false);\n  const [searchTerm, setSearchTerm] = useState(\"\");\n  const [filterAction, setFilterAction] = useState<string>(\"all\");\n  const [selectedEntry, setSelectedEntry] = useState<HistoryEntry | null>(null);\n  const [compareEntry, setCompareEntry] = useState<HistoryEntry | null>(null);\n\n  const store = useUnifiedRuleStore();\n  const historyInfo = store.getHistoryInfo();\n  const { entries: history, current: historyIndex } = historyInfo;\n  const { setRule, canUndo, canRedo, undo, redo } = store;\n\n  // Filter history entries\n  const filteredHistory = useMemo(() => {\n    return history.filter((entry: HistoryEntry) => {\n      const matchesSearch = searchTerm\n        ? entry.description.toLowerCase().includes(searchTerm.toLowerCase()) ||\n          entry.action.toLowerCase().includes(searchTerm.toLowerCase())\n        : true;\n\n      const matchesFilter =\n        filterAction === \"all\" || entry.action === filterAction;\n\n      return matchesSearch && matchesFilter;\n    });\n  }, [history, searchTerm, filterAction]);\n\n  // Get unique actions for filter\n  const uniqueActions = useMemo(() => {\n    const actions = new Set(history.map((entry: HistoryEntry) => entry.action));\n    return [\"all\", ...Array.from(actions)];\n  }, [history]);\n\n  const handleCheckout = (entry: HistoryEntry, index: number) => {\n    setRule(\n      entry.rule,\n      \"Checkout\",\n      `Checked out to version from ${format(entry.timestamp, \"PPp\")}`,\n    );\n    toast.success(`Checked out to version ${index + 1}`);\n    setOpen(false);\n  };\n\n  const getActionIcon = (action: string) => {\n    switch (action.toLowerCase()) {\n      case \"add\":\n      case \"create\":\n        return <CheckCircle className=\"h-4 w-4 text-green-500\" />;\n      case \"remove\":\n      case \"delete\":\n        return <XCircle className=\"h-4 w-4 text-red-500\" />;\n      case \"update\":\n      case \"edit\":\n        return <GitBranch className=\"h-4 w-4 text-blue-500\" />;\n      default:\n        return <Clock className=\"h-4 w-4 text-gray-500\" />;\n    }\n  };\n\n  return (\n    <>\n      <Button\n        variant=\"ghost\"\n        size=\"sm\"\n        onClick={() => setOpen(true)}\n        className={cn(\"gap-2 rounded-md\", className)}\n      >\n        <Clock className=\"h-4 w-4\" />\n        History\n      </Button>\n\n      <ZoomDialog open={open} onOpenChange={setOpen}>\n        <ZoomDialogContent className=\"max-w-6xl h-[90vh] flex flex-col overflow-hidden shadow-lg rounded-lg\">\n          <ZoomDialogHeader className=\"shrink-0 border-b p-6\">\n            <div className=\"flex items-center gap-3\">\n              <div className=\"p-2 rounded-md bg-primary/10\">\n                <Clock className=\"h-5 w-5 text-primary\" />\n              </div>\n              <div>\n                <ZoomDialogTitle className=\"text-xl font-semibold\">\n                  Version History\n                </ZoomDialogTitle>\n                <ZoomDialogDescription className=\"text-muted-foreground\">\n                  View and manage the history of changes to your rule\n                </ZoomDialogDescription>\n              </div>\n            </div>\n          </ZoomDialogHeader>\n\n          <div className=\"flex-1 flex flex-col gap-6 overflow-hidden p-0 pt-4\">\n            {/* Controls */}\n            <div className=\"flex items-center gap-4\">\n              <div className=\"relative flex-1\">\n                <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n                <Input\n                  placeholder=\"Search history...\"\n                  value={searchTerm}\n                  onChange={(e) => setSearchTerm(e.target.value)}\n                  className=\"pl-9 rounded-md\"\n                />\n              </div>\n              <Select value={filterAction} onValueChange={setFilterAction}>\n                <SelectTrigger className=\"w-[180px] rounded-md\">\n                  <SelectValue placeholder=\"Filter actions\" />\n                </SelectTrigger>\n                <SelectContent className=\"rounded-md\">\n                  {uniqueActions.map((action: string) => (\n                    <SelectItem\n                      key={action}\n                      value={action}\n                      className=\"rounded-md\"\n                    >\n                      {action === \"all\" ? \"All Actions\" : action}\n                    </SelectItem>\n                  ))}\n                </SelectContent>\n              </Select>\n              <div className=\"flex items-center gap-2\">\n                <Button\n                  variant=\"outline\"\n                  size=\"icon\"\n                  onClick={undo}\n                  disabled={!canUndo()}\n                  title=\"Undo\"\n                  className=\"rounded-md\"\n                >\n                  <ArrowLeft className=\"h-4 w-4\" />\n                </Button>\n                <Button\n                  variant=\"outline\"\n                  size=\"icon\"\n                  onClick={redo}\n                  disabled={!canRedo()}\n                  title=\"Redo\"\n                  className=\"rounded-md\"\n                >\n                  <ArrowRight className=\"h-4 w-4\" />\n                </Button>\n              </div>\n            </div>\n\n            {/* History List and Details */}\n            <div className=\"flex-1 min-h-0 overflow-hidden\">\n              <ResizablePanel\n                defaultSize={35}\n                minSize={25}\n                maxSize={50}\n                direction=\"horizontal\"\n                persistId=\"history-panel\"\n                className=\"h-full\"\n                handleClassName=\"mx-2\"\n              >\n                {/* History List */}\n                <Card className=\"h-full flex flex-col overflow-hidden rounded-lg shadow-sm border\">\n                  <CardHeader className=\"py-4 px-6 shrink-0 bg-muted/30 border-b\">\n                    <CardTitle className=\"text-lg font-semibold flex items-center gap-2\">\n                      <GitBranch className=\"h-5 w-5 text-primary\" />\n                      History ({filteredHistory.length} entries)\n                    </CardTitle>\n                  </CardHeader>\n                  <CardContent className=\"flex-1 p-0 overflow-hidden\">\n                    <ScrollArea className=\"h-full\">\n                      <div className=\"p-4 space-y-2\">\n                        {filteredHistory.map((entry) => {\n                          const actualIndex = history.indexOf(entry);\n                          const isCurrent = actualIndex === historyIndex;\n                          const isPast = actualIndex < historyIndex;\n\n                          return (\n                            <Card\n                              key={entry.timestamp}\n                              className={cn(\n                                \"group p-4 cursor-pointer transition-all duration-200 rounded-md border\",\n                                \"hover:shadow-md hover:scale-[1.01]\",\n                                isCurrent && \"ring-2 ring-primary bg-primary/5\",\n                                selectedEntry === entry &&\n                                  \"bg-accent ring-1 ring-accent-foreground/20\",\n                                !isCurrent &&\n                                  !selectedEntry &&\n                                  \"bg-card hover:bg-accent/50\",\n                                isPast && \"opacity-70\",\n                              )}\n                              onClick={() => setSelectedEntry(entry)}\n                            >\n                              <div className=\"flex items-start gap-3\">\n                                {getActionIcon(entry.action)}\n                                <div className=\"flex-1 min-w-0\">\n                                  <div className=\"flex items-center gap-2\">\n                                    <h4 className=\"font-semibold text-sm truncate\">\n                                      {entry.action}\n                                    </h4>\n                                    {isCurrent && (\n                                      <Badge\n                                        className=\"text-xs\"\n                                        variant=\"secondary\"\n                                      >\n                                        Current\n                                      </Badge>\n                                    )}\n                                  </div>\n                                  <p className=\"text-xs text-muted-foreground truncate mt-1\">\n                                    {entry.description}\n                                  </p>\n                                  <div className=\"flex items-center gap-2 mt-2\">\n                                    <span className=\"text-xs text-muted-foreground font-medium\">\n                                      {formatDistanceToNow(entry.timestamp, {\n                                        addSuffix: true,\n                                      })}\n                                    </span>\n                                    <span className=\"text-xs text-muted-foreground/50\">\n                                      •\n                                    </span>\n                                    <span className=\"text-xs font-mono bg-muted px-2 py-0.5 rounded\">\n                                      v{actualIndex + 1}\n                                    </span>\n                                  </div>\n                                </div>\n                                <div className=\"flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity\">\n                                  <Button\n                                    variant=\"ghost\"\n                                    size=\"sm\"\n                                    onClick={(e) => {\n                                      e.stopPropagation();\n                                      handleCheckout(entry, actualIndex);\n                                    }}\n                                    disabled={isCurrent}\n                                    title=\"Checkout this version\"\n                                    className=\"h-8 w-8 p-0 rounded-md hover:bg-accent\"\n                                  >\n                                    <RotateCcw className=\"h-3 w-3\" />\n                                  </Button>\n                                  <Button\n                                    variant=\"ghost\"\n                                    size=\"sm\"\n                                    onClick={(e) => {\n                                      e.stopPropagation();\n                                      setCompareEntry(\n                                        entry === compareEntry ? null : entry,\n                                      );\n                                    }}\n                                    title=\"Compare with selected\"\n                                    className=\"h-8 w-8 p-0 rounded-md hover:bg-accent\"\n                                  >\n                                    <Eye className=\"h-3 w-3\" />\n                                  </Button>\n                                </div>\n                              </div>\n                            </Card>\n                          );\n                        })}\n                      </div>\n                    </ScrollArea>\n                  </CardContent>\n                </Card>\n\n                {/* Details/Diff View */}\n                <Card className=\"h-full flex flex-col overflow-hidden rounded-lg shadow-sm border\">\n                  <CardHeader className=\"py-4 px-6 shrink-0 bg-muted/30 border-b\">\n                    <CardTitle className=\"text-lg font-semibold flex items-center gap-2\">\n                      <Eye className=\"h-5 w-5 text-primary\" />\n                      Version Details\n                    </CardTitle>\n                  </CardHeader>\n                  <CardContent className=\"flex-1 p-0 overflow-hidden\">\n                    {selectedEntry ? (\n                      <Tabs\n                        defaultValue=\"details\"\n                        className=\"h-full flex flex-col overflow-hidden\"\n                      >\n                        <TabsList className=\"m-4 mb-0 shrink-0 bg-muted/50 p-1 rounded-lg\">\n                          <TabsTrigger\n                            value=\"details\"\n                            className=\"flex items-center gap-2 rounded-md data-[state=active]:bg-background data-[state=active]:shadow-sm transition-all\"\n                          >\n                            <Eye className=\"h-4 w-4\" />\n                            Details\n                          </TabsTrigger>\n                          <TabsTrigger\n                            value=\"changes\"\n                            className=\"flex items-center gap-2 rounded-md data-[state=active]:bg-background data-[state=active]:shadow-sm transition-all\"\n                          >\n                            <GitBranch className=\"h-4 w-4\" />\n                            Changes\n                          </TabsTrigger>\n                          <TabsTrigger\n                            value=\"json\"\n                            className=\"flex items-center gap-2 rounded-md data-[state=active]:bg-background data-[state=active]:shadow-sm transition-all\"\n                          >\n                            <ArrowRight className=\"h-4 w-4\" />\n                            JSON\n                          </TabsTrigger>\n                          {compareEntry && (\n                            <TabsTrigger\n                              value=\"compare\"\n                              className=\"flex items-center gap-2 rounded-md data-[state=active]:bg-background data-[state=active]:shadow-sm transition-all\"\n                            >\n                              <ArrowLeft className=\"h-4 w-4\" />\n                              Compare\n                            </TabsTrigger>\n                          )}\n                        </TabsList>\n\n                        <TabsContent\n                          value=\"details\"\n                          className=\"flex-1 overflow-auto p-0\"\n                        >\n                          <div className=\"space-y-6 p-6\">\n                            <div className=\"bg-accent/50 p-5 rounded-lg border\">\n                              <div className=\"flex items-center gap-3 mb-4\">\n                                <div className=\"p-2 rounded-md bg-primary/10\">\n                                  <CheckCircle className=\"h-5 w-5 text-primary\" />\n                                </div>\n                                <h4 className=\"font-semibold text-lg\">\n                                  Version Information\n                                </h4>\n                              </div>\n                              <div className=\"grid grid-cols-1 gap-4\">\n                                <div className=\"flex justify-between items-center p-3 bg-background rounded-md border\">\n                                  <span className=\"text-sm font-medium text-muted-foreground\">\n                                    Version:\n                                  </span>\n                                  <span className=\"text-sm font-mono bg-primary/10 text-primary px-2 py-1 rounded\">\n                                    v{history.indexOf(selectedEntry) + 1}\n                                  </span>\n                                </div>\n                                <div className=\"flex justify-between items-center p-3 bg-background rounded-md border\">\n                                  <span className=\"text-sm font-medium text-muted-foreground\">\n                                    Action:\n                                  </span>\n                                  <div className=\"flex items-center gap-2\">\n                                    {getActionIcon(selectedEntry.action)}\n                                    <span className=\"text-sm font-medium\">\n                                      {selectedEntry.action}\n                                    </span>\n                                  </div>\n                                </div>\n                                <div className=\"flex justify-between items-center p-3 bg-background rounded-md border\">\n                                  <span className=\"text-sm font-medium text-muted-foreground\">\n                                    Time:\n                                  </span>\n                                  <span className=\"text-sm font-mono\">\n                                    {format(selectedEntry.timestamp, \"PPp\")}\n                                  </span>\n                                </div>\n                              </div>\n                            </div>\n\n                            <div className=\"bg-muted/50 p-5 rounded-lg border\">\n                              <div className=\"flex items-center gap-3 mb-4\">\n                                <div className=\"p-2 rounded-md bg-muted\">\n                                  <ArrowRight className=\"h-5 w-5 text-muted-foreground\" />\n                                </div>\n                                <h4 className=\"font-semibold text-lg\">\n                                  Description\n                                </h4>\n                              </div>\n                              <div className=\"p-4 bg-background rounded-md border\">\n                                <p className=\"text-sm leading-relaxed\">\n                                  {selectedEntry.description}\n                                </p>\n                              </div>\n                            </div>\n                          </div>\n                        </TabsContent>\n\n                        <TabsContent\n                          value=\"changes\"\n                          className=\"flex-1 overflow-hidden p-0\"\n                        >\n                          <div className=\"h-full p-6\">\n                            {selectedEntry.changes ? (\n                              <div className=\"h-full bg-card rounded-lg border overflow-hidden\">\n                                <DiffViewer\n                                  oldValue={selectedEntry.changes.before}\n                                  newValue={selectedEntry.changes.after}\n                                  oldTitle=\"Before\"\n                                  newTitle=\"After\"\n                                  title=\"Changes\"\n                                  className=\"h-full rounded-lg\"\n                                />\n                              </div>\n                            ) : (\n                              <div className=\"h-full flex items-center justify-center\">\n                                <div className=\"text-center space-y-4\">\n                                  <div className=\"p-4 rounded-lg bg-muted/50 w-fit mx-auto\">\n                                    <GitBranch className=\"h-12 w-12 text-muted-foreground\" />\n                                  </div>\n                                  <div>\n                                    <h3 className=\"text-lg font-medium mb-2\">\n                                      No Change Details\n                                    </h3>\n                                    <p className=\"text-sm text-muted-foreground\">\n                                      Change tracking was not available for this\n                                      version\n                                    </p>\n                                  </div>\n                                </div>\n                              </div>\n                            )}\n                          </div>\n                        </TabsContent>\n\n                        <TabsContent\n                          value=\"json\"\n                          className=\"flex-1 overflow-hidden p-0\"\n                        >\n                          <ScrollArea className=\"h-full\">\n                            <div className=\"p-6\">\n                              <Card className=\"overflow-hidden rounded-lg shadow-sm border\">\n                                <CardContent className=\"p-6\">\n                                  <div className=\"flex items-center gap-3 mb-4\">\n                                    <div className=\"p-2 rounded-md bg-primary/10\">\n                                      <ArrowRight className=\"h-5 w-5 text-primary\" />\n                                    </div>\n                                    <h4 className=\"font-semibold text-lg\">\n                                      Rule JSON Structure\n                                    </h4>\n                                  </div>\n                                  <div className=\"bg-background rounded-md border overflow-hidden\">\n                                    <JsonViewer\n                                      data={selectedEntry.rule}\n                                      rootName=\"rule\"\n                                      defaultExpanded={true}\n                                      className=\"max-w-full\"\n                                      highlightLogicalOperators={true}\n                                    />\n                                  </div>\n                                </CardContent>\n                              </Card>\n                            </div>\n                          </ScrollArea>\n                        </TabsContent>\n\n                        {compareEntry && (\n                          <TabsContent\n                            value=\"compare\"\n                            className=\"flex-1 overflow-hidden p-0\"\n                          >\n                            <div className=\"h-full p-6\">\n                              <div className=\"h-full bg-card rounded-lg border overflow-hidden\">\n                                <div className=\"p-4 bg-muted/30 border-b\">\n                                  <div className=\"flex items-center gap-3\">\n                                    <div className=\"p-2 rounded-md bg-primary/10\">\n                                      <ArrowLeft className=\"h-5 w-5 text-primary\" />\n                                    </div>\n                                    <div>\n                                      <h4 className=\"font-semibold text-lg\">\n                                        Version Comparison\n                                      </h4>\n                                      <p className=\"text-sm text-muted-foreground\">\n                                        Comparing v\n                                        {history.indexOf(compareEntry) + 1} → v\n                                        {history.indexOf(selectedEntry) + 1}\n                                      </p>\n                                    </div>\n                                  </div>\n                                </div>\n                                <DiffViewer\n                                  oldValue={compareEntry.rule}\n                                  newValue={selectedEntry.rule}\n                                  oldTitle={`Version ${history.indexOf(compareEntry) + 1}`}\n                                  newTitle={`Version ${history.indexOf(selectedEntry) + 1}`}\n                                  title={`Comparing v${history.indexOf(compareEntry) + 1} → v${history.indexOf(selectedEntry) + 1}`}\n                                  className=\"flex-1\"\n                                />\n                              </div>\n                            </div>\n                          </TabsContent>\n                        )}\n                      </Tabs>\n                    ) : (\n                      <div className=\"h-full flex items-center justify-center p-8\">\n                        <div className=\"text-center space-y-4\">\n                          <div className=\"p-6 rounded-lg bg-muted/50 w-fit mx-auto\">\n                            <Eye className=\"h-16 w-16 text-muted-foreground\" />\n                          </div>\n                          <div>\n                            <h3 className=\"text-xl font-medium mb-2\">\n                              Select a Version\n                            </h3>\n                            <p className=\"text-sm text-muted-foreground max-w-sm\">\n                              Choose a history entry from the list to view its\n                              details, changes, and JSON structure\n                            </p>\n                          </div>\n                        </div>\n                      </div>\n                    )}\n                  </CardContent>\n                </Card>\n              </ResizablePanel>\n            </div>\n          </div>\n        </ZoomDialogContent>\n      </ZoomDialog>\n    </>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/ImportExport.tsx",
    "content": "import React from \"react\";\nimport { Button } from \"./ui/button\";\nimport { Upload, Download } from \"lucide-react\";\nimport { Input } from \"./ui/input\";\nimport type { ImportExportProps } from \"../types\";\nimport type { RuleType } from \"@usex/rule-engine\";\nimport { cn } from \"../lib/utils\";\n\nexport const ImportExport: React.FC<ImportExportProps> = ({\n  onImport,\n  onExport,\n  className,\n}) => {\n  const fileInputRef = React.useRef<HTMLInputElement>(null);\n\n  const handleExport = () => {\n    const rule = onExport();\n    const json = JSON.stringify(rule, null, 2);\n    const blob = new Blob([json], { type: \"application/json\" });\n    const url = URL.createObjectURL(blob);\n    const a = document.createElement(\"a\");\n    a.href = url;\n    a.download = `rule-${Date.now()}.json`;\n    document.body.appendChild(a);\n    a.click();\n    document.body.removeChild(a);\n    URL.revokeObjectURL(url);\n  };\n\n  const handleImport = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const file = event.target.files?.[0];\n    if (!file) return;\n\n    const reader = new FileReader();\n    reader.onload = (e) => {\n      try {\n        const content = e.target?.result as string;\n        const rule: RuleType = JSON.parse(content);\n        onImport(rule);\n      } catch (error) {\n        console.error(\"Failed to import rule:\", error);\n        console.error(\"Invalid rule JSON file\");\n      }\n    };\n    reader.readAsText(file);\n\n    // Reset the input\n    if (fileInputRef.current) {\n      fileInputRef.current.value = \"\";\n    }\n  };\n\n  return (\n    <div className={cn(\"flex gap-2\", className)}>\n      <Input\n        ref={fileInputRef}\n        type=\"file\"\n        accept=\".json,application/json\"\n        onChange={handleImport}\n        className=\"hidden\"\n        id=\"rule-import\"\n      />\n      <Button\n        type=\"button\"\n        variant=\"outline\"\n        size=\"sm\"\n        onClick={() => fileInputRef.current?.click()}\n      >\n        <Upload className=\"h-4 w-4 mr-2\" />\n        Import\n      </Button>\n      <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleExport}>\n        <Download className=\"h-4 w-4 mr-2\" />\n        Export\n      </Button>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/JsonViewer.tsx",
    "content": "import React, { useMemo } from \"react\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Button } from \"./ui/button\";\nimport { Badge } from \"./ui/badge\";\nimport {\n  Upload,\n  Minimize2,\n  Maximize2,\n  Download,\n  Copy,\n  Check,\n} from \"lucide-react\";\nimport { cn } from \"../lib/utils\";\nimport type { RuleType } from \"@usex/rule-engine\";\n\ninterface JsonViewerProps {\n  rule: RuleType;\n  className?: string;\n  onImport?: (rule: RuleType) => void;\n  expanded?: boolean;\n  onExpandedChange?: (expanded: boolean) => void;\n}\n\nexport const JsonViewer: React.FC<JsonViewerProps> = ({\n  rule,\n  className,\n  onImport,\n  expanded = false,\n  onExpandedChange,\n}) => {\n  const [copied, setCopied] = React.useState(false);\n  const fileInputRef = React.useRef<HTMLInputElement>(null);\n\n  const jsonString = useMemo(() => {\n    return JSON.stringify(rule, null, 2);\n  }, [rule]);\n\n  const handleCopy = async () => {\n    try {\n      await navigator.clipboard.writeText(jsonString);\n      setCopied(true);\n      setTimeout(() => setCopied(false), 2000);\n    } catch (error) {\n      console.error(\"Failed to copy:\", error);\n    }\n  };\n\n  const handleExport = () => {\n    const blob = new Blob([jsonString], { type: \"application/json\" });\n    const url = URL.createObjectURL(blob);\n    const a = document.createElement(\"a\");\n    a.href = url;\n    a.download = `rule-${Date.now()}.json`;\n    document.body.appendChild(a);\n    a.click();\n    document.body.removeChild(a);\n    URL.revokeObjectURL(url);\n  };\n\n  const handleImport = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const file = event.target.files?.[0];\n    if (!file || !onImport) return;\n\n    const reader = new FileReader();\n    reader.onload = (e) => {\n      try {\n        const content = e.target?.result as string;\n        const importedRule: RuleType = JSON.parse(content);\n        onImport(importedRule);\n      } catch (error) {\n        console.error(\"Failed to import rule:\", error);\n      }\n    };\n    reader.readAsText(file);\n\n    if (fileInputRef.current) {\n      fileInputRef.current.value = \"\";\n    }\n  };\n\n  const lineCount = jsonString.split(\"\\n\").length;\n\n  return (\n    <Card className={cn(\"overflow-hidden\", className)}>\n      <CardHeader className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between space-y-2 sm:space-y-0 pb-3\">\n        <div className=\"flex items-center gap-2\">\n          <CardTitle className=\"text-sm sm:text-base font-medium\">\n            Rule JSON\n          </CardTitle>\n          <Badge variant=\"secondary\" className=\"text-xs\">\n            {lineCount} lines\n          </Badge>\n        </div>\n        <div className=\"flex items-center gap-1 justify-end sm:justify-start\">\n          {onImport && (\n            <>\n              <input\n                ref={fileInputRef}\n                type=\"file\"\n                accept=\".json,application/json\"\n                onChange={handleImport}\n                className=\"hidden\"\n              />\n              <Button\n                variant=\"ghost\"\n                size=\"sm\"\n                className=\"h-7 w-7 p-0 sm:h-8 sm:w-8\"\n                onClick={() => fileInputRef.current?.click()}\n                title=\"Import JSON\"\n              >\n                <Upload className=\"h-3 w-3 sm:h-4 sm:w-4\" />\n              </Button>\n            </>\n          )}\n          <Button\n            variant=\"ghost\"\n            size=\"sm\"\n            className=\"h-7 w-7 p-0 sm:h-8 sm:w-8\"\n            onClick={handleExport}\n            title=\"Export JSON\"\n          >\n            <Download className=\"h-3 w-3 sm:h-4 sm:w-4\" />\n          </Button>\n          <Button\n            variant=\"ghost\"\n            size=\"sm\"\n            className=\"h-7 w-7 p-0 sm:h-8 sm:w-8\"\n            onClick={handleCopy}\n            title=\"Copy JSON\"\n          >\n            {copied ? (\n              <Check className=\"h-3 w-3 sm:h-4 sm:w-4 text-green-600\" />\n            ) : (\n              <Copy className=\"h-3 w-3 sm:h-4 sm:w-4\" />\n            )}\n          </Button>\n          {onExpandedChange && (\n            <Button\n              variant=\"ghost\"\n              size=\"sm\"\n              className=\"h-7 w-7 p-0 sm:h-8 sm:w-8\"\n              onClick={() => onExpandedChange(!expanded)}\n              title={expanded ? \"Minimize\" : \"Maximize\"}\n            >\n              {expanded ? (\n                <Minimize2 className=\"h-3 w-3 sm:h-4 sm:w-4\" />\n              ) : (\n                <Maximize2 className=\"h-3 w-3 sm:h-4 sm:w-4\" />\n              )}\n            </Button>\n          )}\n        </div>\n      </CardHeader>\n      <CardContent className=\"p-0\">\n        <div\n          className={cn(\n            \"overflow-auto bg-muted/50 dark:bg-muted/20\",\n            expanded ? \"max-h-[80vh]\" : \"max-h-[300px] sm:max-h-[400px]\",\n          )}\n        >\n          <pre className=\"p-3 sm:p-4 text-xs sm:text-sm\">\n            <code className=\"font-mono leading-relaxed\">{jsonString}</code>\n          </pre>\n        </div>\n      </CardContent>\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/JsonVisualizer.tsx",
    "content": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n  MoreHorizontal,\n  Copy,\n  ChevronUp,\n  ChevronRight,\n  ChevronDown,\n  Check,\n} from \"lucide-react\";\nimport { cn } from \"../lib/utils\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"./ui/tooltip\";\n\ninterface JsonViewerProps {\n  data: any;\n  rootName?: string;\n  defaultExpanded?: boolean;\n  className?: string;\n  highlightLogicalOperators?: boolean;\n}\n\nexport function JsonViewer({\n  data,\n  rootName = \"root\",\n  defaultExpanded = true,\n  className,\n  highlightLogicalOperators = false,\n}: JsonViewerProps) {\n  return (\n    <TooltipProvider>\n      <div className={cn(\"font-mono text-sm\", className)}>\n        <JsonNode\n          name={rootName}\n          data={data}\n          isRoot={true}\n          defaultExpanded={defaultExpanded}\n          highlightLogicalOperators={highlightLogicalOperators}\n        />\n      </div>\n    </TooltipProvider>\n  );\n}\n\ninterface JsonNodeProps {\n  name: string;\n  data: any;\n  isRoot?: boolean;\n  defaultExpanded?: boolean;\n  level?: number;\n  highlightLogicalOperators?: boolean;\n}\n\nfunction JsonNode({\n  name,\n  data,\n  isRoot = false,\n  defaultExpanded = true,\n  level = 0,\n  highlightLogicalOperators = false,\n}: JsonNodeProps) {\n  const [isExpanded, setIsExpanded] = React.useState(defaultExpanded);\n  const [isCopied, setIsCopied] = React.useState(false);\n\n  const handleToggle = () => {\n    setIsExpanded(!isExpanded);\n  };\n\n  const copyToClipboard = (e: React.MouseEvent) => {\n    e.stopPropagation();\n    navigator.clipboard.writeText(JSON.stringify(data, null, 2));\n    setIsCopied(true);\n    setTimeout(() => setIsCopied(false), 2000);\n  };\n\n  const dataType =\n    data === null ? \"null\" : Array.isArray(data) ? \"array\" : typeof data;\n  const isExpandable =\n    data !== null &&\n    data !== undefined &&\n    !(data instanceof Date) &&\n    (dataType === \"object\" || dataType === \"array\");\n  const itemCount =\n    isExpandable && data !== null && data !== undefined\n      ? Object.keys(data).length\n      : 0;\n\n  // Check if this is a logical operator node (or, and, none)\n  const isLogicalOperator =\n    highlightLogicalOperators &&\n    (name === \"or\" || name === \"and\" || name === \"none\");\n  const isRootOperator =\n    highlightLogicalOperators &&\n    isRoot &&\n    data &&\n    typeof data === \"object\" &&\n    (\"or\" in data || \"and\" in data || \"none\" in data);\n\n  return (\n    <div\n      className={cn(\"pl-4 group/object\", level > 0 && \"border-l border-border\")}\n    >\n      <div\n        className={cn(\n          \"flex items-center gap-1 py-1 rounded px-1 -ml-4 cursor-pointer group/property transition-colors\",\n          isRoot && !isRootOperator && \"text-primary font-semibold\",\n          isLogicalOperator &&\n            name === \"or\" &&\n            \"bg-blue-500/10 hover:bg-blue-500/20\",\n          isLogicalOperator &&\n            name === \"and\" &&\n            \"bg-green-500/10 hover:bg-green-500/20\",\n          isLogicalOperator &&\n            name === \"none\" &&\n            \"bg-red-500/10 hover:bg-red-500/20\",\n          isRootOperator && \"bg-primary/5 hover:bg-primary/10\",\n          !isLogicalOperator && !isRootOperator && \"hover:bg-muted/50\",\n        )}\n        onClick={isExpandable ? handleToggle : undefined}\n      >\n        {isExpandable ? (\n          <div className=\"w-4 h-4 flex items-center justify-center\">\n            {isExpanded ? (\n              <ChevronDown className=\"h-3.5 w-3.5 text-muted-foreground\" />\n            ) : (\n              <ChevronRight className=\"h-3.5 w-3.5 text-muted-foreground\" />\n            )}\n          </div>\n        ) : (\n          <div className=\"w-4\" />\n        )}\n\n        <span\n          className={cn(\n            \"font-medium\",\n            isLogicalOperator &&\n              name === \"or\" &&\n              \"text-blue-600 dark:text-blue-400\",\n            isLogicalOperator &&\n              name === \"and\" &&\n              \"text-green-600 dark:text-green-400\",\n            isLogicalOperator &&\n              name === \"none\" &&\n              \"text-red-600 dark:text-red-400\",\n            !isLogicalOperator && \"text-primary\",\n          )}\n        >\n          {isLogicalOperator ? name.toUpperCase() : name}\n        </span>\n\n        <span className=\"text-muted-foreground\">\n          {isExpandable ? (\n            <>\n              {dataType === \"array\" ? \"[\" : \"{\"}\n              {!isExpanded && (\n                <span className=\"text-muted-foreground\">\n                  {\" \"}\n                  {itemCount} {itemCount === 1 ? \"item\" : \"items\"}{\" \"}\n                  {dataType === \"array\" ? \"]\" : \"}\"}\n                </span>\n              )}\n            </>\n          ) : (\n            \":\"\n          )}\n        </span>\n\n        {!isExpandable && <JsonValue data={data} />}\n\n        {!isExpandable && <div className=\"w-3.5\" />}\n\n        <button\n          onClick={copyToClipboard}\n          className=\"ml-auto opacity-0 group-hover/property:opacity-100 hover:bg-muted p-1 rounded\"\n          title=\"Copy to clipboard\"\n        >\n          {isCopied ? (\n            <Check className=\"h-3.5 w-3.5 text-green-500\" />\n          ) : (\n            <Copy className=\"h-3.5 w-3.5 text-muted-foreground\" />\n          )}\n        </button>\n      </div>\n\n      {isExpandable && isExpanded && data !== null && data !== undefined && (\n        <div className=\"pl-4\">\n          {Object.keys(data).map((key) => (\n            <JsonNode\n              key={key}\n              name={dataType === \"array\" ? `${key}` : key}\n              data={data[key]}\n              level={level + 1}\n              defaultExpanded={level < 1}\n              highlightLogicalOperators={highlightLogicalOperators}\n            />\n          ))}\n          <div className=\"text-muted-foreground pl-4 py-1\">\n            {dataType === \"array\" ? \"]\" : \"}\"}\n          </div>\n        </div>\n      )}\n    </div>\n  );\n}\n\n// Update the JsonValue function to make the entire row clickable with an expand icon\nfunction JsonValue({ data }: { data: any }) {\n  const [isExpanded, setIsExpanded] = React.useState(false);\n  const dataType = typeof data;\n  const TEXT_LIMIT = 80; // Character limit before truncation\n\n  if (data === null) {\n    return <span className=\"text-rose-500\">null</span>;\n  }\n\n  if (data === undefined) {\n    return <span className=\"text-muted-foreground\">undefined</span>;\n  }\n\n  if (data instanceof Date) {\n    return <span className=\"text-purple-500\">{data.toISOString()}</span>;\n  }\n\n  switch (dataType) {\n    case \"string\":\n      if (data.length > TEXT_LIMIT) {\n        return (\n          <div\n            className=\"text-emerald-500 flex-1 flex items-center relative group cursor-pointer\"\n            onClick={(e) => {\n              e.stopPropagation();\n              setIsExpanded(!isExpanded);\n            }}\n          >\n            {`\"`}\n            {isExpanded ? (\n              <span className=\"inline-block max-w-full\">{data}</span>\n            ) : (\n              <Tooltip delayDuration={300}>\n                <TooltipTrigger asChild>\n                  <span className=\"inline-block max-w-full\">\n                    {data.substring(0, TEXT_LIMIT)}...\n                  </span>\n                </TooltipTrigger>\n                <TooltipContent\n                  side=\"bottom\"\n                  className=\"max-w-md text-xs p-2 break-words\"\n                >\n                  {data}\n                </TooltipContent>\n              </Tooltip>\n            )}\n            {`\"`}\n            <div className=\"absolute right-0 top-1/2 -translate-y-1/2 translate-x-[calc(100%+4px)] opacity-0 group-hover:opacity-100 transition-opacity\">\n              {isExpanded ? (\n                <ChevronUp className=\"h-3 w-3 text-muted-foreground\" />\n              ) : (\n                <MoreHorizontal className=\"h-3 w-3 text-muted-foreground\" />\n              )}\n            </div>\n          </div>\n        );\n      }\n      return <span className=\"text-emerald-500\">{`\"${data}\"`}</span>;\n    case \"number\":\n      return <span className=\"text-amber-500\">{data}</span>;\n    case \"boolean\":\n      return <span className=\"text-blue-500\">{data.toString()}</span>;\n    default:\n      return <span>{String(data)}</span>;\n  }\n}\n"
  },
  {
    "path": "packages/builder/src/components/ModernConstraintEditor.tsx",
    "content": "import React from \"react\";\nimport { useSortable } from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { Card } from \"./ui/card\";\nimport { Button } from \"./ui/button\";\nimport { Badge } from \"./ui/badge\";\nimport { Input } from \"./ui/input\";\nimport { Label } from \"./ui/label\";\nimport { Separator } from \"./ui/separator\";\nimport { Trash2, Info, GripVertical, Copy, AlertCircle } from \"lucide-react\";\nimport { DynamicFieldSelector } from \"./DynamicFieldSelector\";\nimport { OperatorSelector } from \"./OperatorSelector\";\nimport { OperatorHandler } from \"./operators\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"./ui/tooltip\";\nimport type { Constraint } from \"@usex/rule-engine\";\nimport type { FieldConfig } from \"../types\";\nimport { getOperatorConfig } from \"../utils/operators\";\nimport { cn } from \"../lib/utils\";\n\ninterface ModernConstraintEditorProps {\n  id: string;\n  constraint: Constraint;\n  fields?: FieldConfig[];\n  sampleData?: Record<string, any>;\n  customOperators?: Record<string, any>;\n  onUpdate: (constraint: Constraint) => void;\n  onRemove: () => void;\n  onDuplicate: () => void;\n  readOnly?: boolean;\n}\n\nexport const ModernConstraintEditor: React.FC<ModernConstraintEditorProps> = ({\n  id,\n  constraint,\n  fields,\n  sampleData,\n  customOperators,\n  onUpdate,\n  onRemove,\n  onDuplicate,\n  readOnly = false,\n}) => {\n  const {\n    attributes,\n    listeners,\n    setNodeRef,\n    transform,\n    transition,\n    isDragging,\n  } = useSortable({ id, disabled: readOnly });\n\n  const style = {\n    transform: CSS.Transform.toString(transform),\n    transition,\n  };\n\n  const operatorConfig = getOperatorConfig(constraint.operator);\n  const selectedField = fields?.find((f) => f.name === constraint.field);\n\n  return (\n    <div\n      ref={setNodeRef}\n      style={style}\n      className={cn(\"animate-fadeIn\", isDragging && \"opacity-50\")}\n    >\n      <Card className=\"overflow-hidden hover:shadow-md transition-shadow\">\n        <div className=\"p-4\">\n          <div className=\"flex items-start gap-3\">\n            {!readOnly && (\n              <button\n                className=\"mt-1 cursor-grab active:cursor-grabbing text-muted-foreground hover:text-foreground\"\n                {...attributes}\n                {...listeners}\n              >\n                <GripVertical className=\"h-5 w-5\" />\n              </button>\n            )}\n\n            <div className=\"flex-1 space-y-4\">\n              {/* Field and Operator Row */}\n              <div className=\"grid grid-cols-1 md:grid-cols-2 gap-3\">\n                <div className=\"space-y-2\">\n                  <div className=\"flex items-center gap-2\">\n                    <Label\n                      htmlFor={`${id}-field`}\n                      className=\"text-sm font-medium\"\n                    >\n                      Field\n                    </Label>\n                    {selectedField?.description && (\n                      <TooltipProvider>\n                        <Tooltip>\n                          <TooltipTrigger>\n                            <Info className=\"h-3 w-3 text-muted-foreground\" />\n                          </TooltipTrigger>\n                          <TooltipContent>\n                            <p className=\"max-w-xs\">\n                              {selectedField.description}\n                            </p>\n                          </TooltipContent>\n                        </Tooltip>\n                      </TooltipProvider>\n                    )}\n                  </div>\n                  <DynamicFieldSelector\n                    value={constraint.field}\n                    onChange={(field) => onUpdate({ ...constraint, field })}\n                    fields={fields}\n                    sampleData={sampleData}\n                    disabled={readOnly}\n                    allowCustom={true}\n                    showJsonPath={true}\n                  />\n                </div>\n\n                <div className=\"space-y-2\">\n                  <Label\n                    htmlFor={`${id}-operator`}\n                    className=\"text-sm font-medium\"\n                  >\n                    Operator\n                  </Label>\n                  <OperatorSelector\n                    value={constraint.operator}\n                    onChange={(operator) =>\n                      onUpdate({ ...constraint, operator })\n                    }\n                    field={constraint.field}\n                    disabled={readOnly}\n                    customOperators={customOperators}\n                  />\n                </div>\n              </div>\n\n              {/* Value Input */}\n              {operatorConfig?.valueType !== \"none\" && (\n                <div className=\"space-y-2\">\n                  <div className=\"flex items-center gap-2\">\n                    <Label\n                      htmlFor={`${id}-value`}\n                      className=\"text-sm font-medium\"\n                    >\n                      Value\n                    </Label>\n                    {operatorConfig?.valueType && (\n                      <Badge variant=\"outline\" className=\"text-xs\">\n                        {operatorConfig.valueType}\n                      </Badge>\n                    )}\n                  </div>\n                  <OperatorHandler\n                    operator={constraint.operator}\n                    value={constraint.value}\n                    onChange={(value) => onUpdate({ ...constraint, value })}\n                    field={constraint.field}\n                    fieldType={selectedField?.type}\n                    sampleData={sampleData}\n                    disabled={readOnly}\n                  />\n                </div>\n              )}\n\n              {/* Error Message */}\n              <div className=\"space-y-2\">\n                <div className=\"flex items-center gap-2\">\n                  <Label\n                    htmlFor={`${id}-message`}\n                    className=\"text-sm font-medium\"\n                  >\n                    Error Message\n                  </Label>\n                  <Badge variant=\"outline\" className=\"text-xs\">\n                    Optional\n                  </Badge>\n                </div>\n                <div className=\"relative\">\n                  <AlertCircle className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n                  <Input\n                    id={`${id}-message`}\n                    value={constraint.message || \"\"}\n                    onChange={(e) =>\n                      onUpdate({\n                        ...constraint,\n                        message: e.target.value || undefined,\n                      })\n                    }\n                    placeholder=\"Custom error message when this rule fails\"\n                    disabled={readOnly}\n                    className=\"pl-10\"\n                  />\n                </div>\n              </div>\n            </div>\n\n            {/* Actions */}\n            {!readOnly && (\n              <div className=\"flex flex-col gap-1\">\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"h-8 w-8\"\n                  onClick={onDuplicate}\n                >\n                  <Copy className=\"h-4 w-4\" />\n                </Button>\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"h-8 w-8 text-destructive hover:text-destructive\"\n                  onClick={onRemove}\n                >\n                  <Trash2 className=\"h-4 w-4\" />\n                </Button>\n              </div>\n            )}\n          </div>\n\n          {/* Preview */}\n          <Separator className=\"my-4\" />\n          <div className=\"text-xs text-muted-foreground font-mono\">\n            {constraint.field} {operatorConfig?.label || constraint.operator}\n            {constraint.value !== undefined && (\n              <> {JSON.stringify(constraint.value)}</>\n            )}\n          </div>\n        </div>\n      </Card>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/ModernRuleBuilder.tsx",
    "content": "import React from \"react\";\nimport {\n  useSensors,\n  useSensor,\n  PointerSensor,\n  DragOverlay,\n  DndContext,\n  closestCenter,\n} from \"@dnd-kit/core\";\nimport type { DragStartEvent, DragEndEvent } from \"@dnd-kit/core\";\nimport {\n  verticalListSortingStrategy,\n  SortableContext,\n} from \"@dnd-kit/sortable\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Button } from \"./ui/button\";\nimport { Badge } from \"./ui/badge\";\nimport { Separator } from \"./ui/separator\";\nimport { JsonViewer } from \"./JsonViewer\";\nimport { DraggableConditionGroup } from \"./DraggableConditionGroup\";\nimport { ModernConstraintEditor } from \"./ModernConstraintEditor\";\nimport { ThemeToggle } from \"./ThemeToggle\";\nimport { Undo2, Save, Redo2, Plus, HelpCircle, FileJson } from \"lucide-react\";\nimport { useRuleStore } from \"../stores/rule-store\";\nimport { useTheme } from \"../hooks/use-theme\";\nimport type { Constraint, ConditionType, Condition } from \"@usex/rule-engine\";\nimport type { FieldConfig } from \"../types\";\nimport { cn } from \"../lib/utils\";\nimport { Toaster } from \"./ui/sonner\";\nimport { toast } from \"sonner\";\n\ninterface ModernRuleBuilderProps {\n  fields?: FieldConfig[];\n  sampleData?: Record<string, any>;\n  onChange?: (rule: any) => void;\n  onSave?: (rule: any) => void | Promise<void>;\n  onExport?: (rule: any, format: \"json\" | \"yaml\") => void;\n  onImport?: (data: string, format: \"json\" | \"yaml\") => void;\n  readOnly?: boolean;\n  className?: string;\n  showJsonViewer?: boolean;\n  showToolbar?: boolean;\n  enableDragDrop?: boolean;\n  enableHistory?: boolean;\n  maxNestingDepth?: number;\n  customOperators?: Record<string, any>;\n  theme?: \"light\" | \"dark\" | \"system\";\n  labels?: {\n    addGroup?: string;\n    addRule?: string;\n    removeGroup?: string;\n    duplicateGroup?: string;\n    or?: string;\n    and?: string;\n    none?: string;\n    noRules?: string;\n    importSuccess?: string;\n    exportSuccess?: string;\n    saveSuccess?: string;\n  };\n  colors?: {\n    or?: string;\n    and?: string;\n    none?: string;\n  };\n}\n\nexport const ModernRuleBuilder: React.FC<ModernRuleBuilderProps> = ({\n  fields = [],\n  sampleData,\n  onChange,\n  onSave,\n  onExport,\n  onImport,\n  readOnly = false,\n  className,\n  showJsonViewer = true,\n  showToolbar = true,\n  enableDragDrop = true,\n  enableHistory = true,\n  maxNestingDepth = 10,\n  customOperators,\n  theme: _propTheme = \"system\",\n  labels = {},\n  colors = {},\n}) => {\n  const { theme: _theme } = useTheme();\n  const { rule, updateConditions, undo, redo, canUndo, canRedo } =\n    useRuleStore();\n\n  const [activeId, setActiveId] = React.useState<string | null>(null);\n  const [expandedJson, setExpandedJson] = React.useState(false);\n  const [isSaving, setIsSaving] = React.useState(false);\n\n  // Merge default labels\n  const mergedLabels = {\n    addGroup: \"Add Condition Group\",\n    addRule: \"Add Rule\",\n    removeGroup: \"Remove Group\",\n    duplicateGroup: \"Duplicate Group\",\n    or: \"OR\",\n    and: \"AND\",\n    none: \"NONE\",\n    noRules: \"No rules defined yet. Start by adding a condition group.\",\n    importSuccess: \"Rule imported successfully\",\n    exportSuccess: \"Rule exported successfully\",\n    saveSuccess: \"Rule saved successfully\",\n    ...labels,\n  };\n\n  const isConstraint = (item: any): item is Constraint => {\n    return \"field\" in item && \"operator\" in item;\n  };\n\n  // Helper functions to find and update nested items\n  const findItemPath = (\n    items: any[],\n    targetId: string,\n    currentPath: number[] = [],\n  ): number[] | null => {\n    for (let i = 0; i < items.length; i++) {\n      const item = items[i];\n      const itemPath = [...currentPath, i];\n\n      if (isConstraint(item)) {\n        // Check if this constraint matches the target ID\n        if (`constraint-${itemPath.join(\"-\")}` === targetId) {\n          return itemPath;\n        }\n      } else {\n        // Check if this condition matches the target ID\n        if (`condition-${itemPath.join(\"-\")}` === targetId) {\n          return itemPath;\n        }\n\n        // Recursively search in nested conditions\n        const type = Object.keys(item).find(\n          (k) => k === \"or\" || k === \"and\" || k === \"none\",\n        ) as ConditionType;\n\n        if (type && item[type]) {\n          const nestedPath = findItemPath(item[type], targetId, itemPath);\n          if (nestedPath) return nestedPath;\n        }\n      }\n    }\n    return null;\n  };\n\n  const updateNestedItem = (\n    conditions: Condition[],\n    path: number[],\n    updater: (item: any) => any,\n  ): Condition[] => {\n    const newConditions = [...conditions];\n    let current: any = newConditions;\n\n    for (let i = 0; i < path.length - 1; i++) {\n      const index = path[i];\n      if (i === 0) {\n        current = current[index];\n      } else {\n        const type = Object.keys(current).find(\n          (k) => k === \"or\" || k === \"and\" || k === \"none\",\n        ) as ConditionType;\n        if (type) {\n          current = current[type][index];\n        }\n      }\n    }\n\n    const lastIndex = path[path.length - 1];\n    const type = Object.keys(current).find(\n      (k) => k === \"or\" || k === \"and\" || k === \"none\",\n    ) as ConditionType;\n\n    if (type) {\n      current[type][lastIndex] = updater(current[type][lastIndex]);\n    }\n\n    return newConditions;\n  };\n\n  const removeNestedItem = (\n    conditions: Condition[],\n    path: number[],\n  ): Condition[] => {\n    const newConditions = [...conditions];\n    let current: any = newConditions;\n\n    for (let i = 0; i < path.length - 1; i++) {\n      const index = path[i];\n      if (i === 0) {\n        current = current[index];\n      } else {\n        const type = Object.keys(current).find(\n          (k) => k === \"or\" || k === \"and\" || k === \"none\",\n        ) as ConditionType;\n        if (type) {\n          current = current[type][index];\n        }\n      }\n    }\n\n    const lastIndex = path[path.length - 1];\n    const type = Object.keys(current).find(\n      (k) => k === \"or\" || k === \"and\" || k === \"none\",\n    ) as ConditionType;\n\n    if (type) {\n      current[type].splice(lastIndex, 1);\n    }\n\n    return newConditions;\n  };\n\n  const sensors = useSensors(\n    useSensor(PointerSensor, {\n      activationConstraint: {\n        distance: 8,\n      },\n    }),\n  );\n\n  // Debounce onChange to prevent infinite loops\n  const onChangeTimerRef = React.useRef<NodeJS.Timeout>(null);\n\n  React.useEffect(() => {\n    if (onChange) {\n      // Clear previous timer\n      if (onChangeTimerRef.current) {\n        clearTimeout(onChangeTimerRef.current);\n      }\n\n      // Set new timer\n      onChangeTimerRef.current = setTimeout(() => {\n        onChange(rule);\n      }, 100);\n    }\n\n    return () => {\n      if (onChangeTimerRef.current) {\n        clearTimeout(onChangeTimerRef.current);\n      }\n    };\n  }, [rule]); // Intentionally omit onChange to prevent loops\n\n  const conditions = React.useMemo(() => {\n    if (!rule.conditions) return [];\n    return Array.isArray(rule.conditions) ? rule.conditions : [rule.conditions];\n  }, [rule.conditions]);\n\n  const handleDragStart = (event: DragStartEvent) => {\n    setActiveId(event.active.id as string);\n  };\n\n  const handleDragEnd = (event: DragEndEvent) => {\n    const { active, over } = event;\n    setActiveId(null);\n\n    if (over && active.id !== over.id) {\n      // Handle reordering logic here\n      // This would involve updating the conditions array\n    }\n  };\n\n  const addRootConditionGroup = (type: \"or\" | \"and\" | \"none\" = \"or\") => {\n    const newCondition: Condition = { [type]: [] };\n    updateConditions([...conditions, newCondition]);\n    toast.success(\"Added new condition group\");\n  };\n\n  const addConstraint = (conditionIndex: number) => {\n    const newConstraint: Constraint = {\n      field: \"\",\n      operator: \"equals\" as any,\n      value: \"\",\n    };\n\n    const updatedConditions = [...conditions];\n    const condition = updatedConditions[conditionIndex];\n    const type = Object.keys(condition).find(\n      (k) => k === \"or\" || k === \"and\" || k === \"none\",\n    ) as ConditionType;\n\n    if (type) {\n      condition[type] = [...(condition[type] || []), newConstraint];\n      updateConditions(updatedConditions);\n      toast.success(\"Added new rule\");\n    }\n  };\n\n  const addNestedGroup = (conditionIndex: number) => {\n    const newCondition: Condition = { and: [] };\n\n    const updatedConditions = [...conditions];\n    const condition = updatedConditions[conditionIndex];\n    const type = Object.keys(condition).find(\n      (k) => k === \"or\" || k === \"and\" || k === \"none\",\n    ) as ConditionType;\n\n    if (type) {\n      condition[type] = [...(condition[type] || []), newCondition];\n      updateConditions(updatedConditions);\n      toast.success(\"Added nested group\");\n    }\n  };\n\n  const updateCondition = (index: number, condition: Condition) => {\n    const updatedConditions = [...conditions];\n    updatedConditions[index] = condition;\n    updateConditions(updatedConditions);\n  };\n\n  const removeCondition = (index: number) => {\n    updateConditions(conditions.filter((_, i) => i !== index));\n    toast.success(\"Removed condition group\");\n  };\n\n  const duplicateCondition = (index: number) => {\n    const conditionToDuplicate = conditions[index];\n    const duplicated = JSON.parse(JSON.stringify(conditionToDuplicate));\n    updateConditions([...conditions, duplicated]);\n    toast.success(\"Duplicated condition group\");\n  };\n\n  const renderItems = (items: any[], parentPath: string, depth: number = 1) => {\n    return items.map((item, index) => {\n      const itemId = `${parentPath}-${index}`;\n      const currentDepth = depth + 1;\n\n      // Check max nesting depth\n      if (currentDepth > maxNestingDepth) {\n        return (\n          <Card key={itemId} className=\"border-destructive\">\n            <CardContent className=\"py-3\">\n              <p className=\"text-sm text-destructive\">\n                Maximum nesting depth ({maxNestingDepth}) reached\n              </p>\n            </CardContent>\n          </Card>\n        );\n      }\n\n      if (isConstraint(item)) {\n        return (\n          <ModernConstraintEditor\n            key={itemId}\n            id={`constraint-${itemId}`}\n            constraint={item}\n            fields={fields}\n            sampleData={sampleData}\n            customOperators={customOperators}\n            onUpdate={(updated) => {\n              const path = findItemPath(conditions, `constraint-${itemId}`);\n              if (path) {\n                const newConditions = updateNestedItem(\n                  conditions,\n                  path,\n                  () => updated,\n                );\n                updateConditions(newConditions);\n              }\n            }}\n            onRemove={() => {\n              const path = findItemPath(conditions, `constraint-${itemId}`);\n              if (path) {\n                const newConditions = removeNestedItem(conditions, path);\n                updateConditions(newConditions);\n                toast.success(\"Rule removed\");\n              }\n            }}\n            onDuplicate={() => {\n              const path = findItemPath(conditions, `constraint-${itemId}`);\n              if (path) {\n                const parentPath = path.slice(0, -1);\n                let parent: any = conditions;\n\n                for (let i = 0; i < parentPath.length; i++) {\n                  if (i === 0) {\n                    parent = parent[parentPath[i]];\n                  } else {\n                    const type = Object.keys(parent).find(\n                      (k) => k === \"or\" || k === \"and\" || k === \"none\",\n                    ) as ConditionType;\n                    if (type) {\n                      parent = parent[type][parentPath[i]];\n                    }\n                  }\n                }\n\n                const type = Object.keys(parent).find(\n                  (k) => k === \"or\" || k === \"and\" || k === \"none\",\n                ) as ConditionType;\n\n                if (type) {\n                  const duplicated = JSON.parse(JSON.stringify(item));\n                  parent[type].push(duplicated);\n                  updateConditions([...conditions]);\n                  toast.success(\"Rule duplicated\");\n                }\n              }\n            }}\n            readOnly={readOnly}\n          />\n        );\n      }\n\n      return (\n        <DraggableConditionGroup\n          key={itemId}\n          id={`condition-${itemId}`}\n          condition={item}\n          depth={currentDepth}\n          labels={mergedLabels}\n          colors={colors}\n          enableDragDrop={enableDragDrop}\n          onUpdate={(updated) => {\n            const path = findItemPath(conditions, `condition-${itemId}`);\n            if (path) {\n              const newConditions = updateNestedItem(\n                conditions,\n                path,\n                () => updated,\n              );\n              updateConditions(newConditions);\n            }\n          }}\n          onRemove={() => {\n            const path = findItemPath(conditions, `condition-${itemId}`);\n            if (path) {\n              const newConditions = removeNestedItem(conditions, path);\n              updateConditions(newConditions);\n              toast.success(mergedLabels.removeGroup);\n            }\n          }}\n          onDuplicate={() => {\n            const path = findItemPath(conditions, `condition-${itemId}`);\n            if (path) {\n              const parentPath = path.slice(0, -1);\n\n              if (parentPath.length === 0) {\n                // Duplicating at root level\n                const duplicated = JSON.parse(JSON.stringify(item));\n                updateConditions([...conditions, duplicated]);\n              } else {\n                // Duplicating nested item\n                let parent: any = conditions;\n\n                for (let i = 0; i < parentPath.length; i++) {\n                  if (i === 0) {\n                    parent = parent[parentPath[i]];\n                  } else {\n                    const type = Object.keys(parent).find(\n                      (k) => k === \"or\" || k === \"and\" || k === \"none\",\n                    ) as ConditionType;\n                    if (type) {\n                      parent = parent[type][parentPath[i]];\n                    }\n                  }\n                }\n\n                const type = Object.keys(parent).find(\n                  (k) => k === \"or\" || k === \"and\" || k === \"none\",\n                ) as ConditionType;\n\n                if (type) {\n                  const duplicated = JSON.parse(JSON.stringify(item));\n                  parent[type].push(duplicated);\n                  updateConditions([...conditions]);\n                }\n              }\n              toast.success(mergedLabels.duplicateGroup);\n            }\n          }}\n          onAddConstraint={() => {\n            const path = findItemPath(conditions, `condition-${itemId}`);\n            if (path) {\n              const newConstraint: Constraint = {\n                field: \"\",\n                operator: \"equals\" as any,\n                value: \"\",\n              };\n\n              const newConditions = updateNestedItem(\n                conditions,\n                path,\n                (item) => {\n                  const type = Object.keys(item).find(\n                    (k) => k === \"or\" || k === \"and\" || k === \"none\",\n                  ) as ConditionType;\n\n                  if (type) {\n                    return {\n                      ...item,\n                      [type]: [...(item[type] || []), newConstraint],\n                    };\n                  }\n                  return item;\n                },\n              );\n\n              updateConditions(newConditions);\n              toast.success(mergedLabels.addRule);\n            }\n          }}\n          onAddGroup={() => {\n            if (currentDepth >= maxNestingDepth) {\n              toast.error(`Maximum nesting depth (${maxNestingDepth}) reached`);\n              return;\n            }\n\n            const path = findItemPath(conditions, `condition-${itemId}`);\n            if (path) {\n              const newCondition: Condition = { and: [] };\n\n              const newConditions = updateNestedItem(\n                conditions,\n                path,\n                (item) => {\n                  const type = Object.keys(item).find(\n                    (k) => k === \"or\" || k === \"and\" || k === \"none\",\n                  ) as ConditionType;\n\n                  if (type) {\n                    return {\n                      ...item,\n                      [type]: [...(item[type] || []), newCondition],\n                    };\n                  }\n                  return item;\n                },\n              );\n\n              updateConditions(newConditions);\n              toast.success(\"Added nested group\");\n            }\n          }}\n          readOnly={readOnly}\n        >\n          {renderItems(\n            item.or || item.and || item.none || [],\n            itemId,\n            currentDepth,\n          )}\n        </DraggableConditionGroup>\n      );\n    });\n  };\n\n  return (\n    <div className={cn(\"space-y-4\", className)}>\n      <Toaster position=\"top-center\" />\n\n      {/* Mobile-First Responsive Header */}\n      <Card>\n        <CardHeader className=\"pb-3\">\n          {/* Mobile: Stack vertically, Desktop: Side by side */}\n          <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 sm:gap-0\">\n            <div className=\"flex items-center gap-2 sm:gap-3\">\n              <CardTitle className=\"text-lg sm:text-xl\">Rule Builder</CardTitle>\n              <Badge variant=\"outline\" className=\"text-xs sm:text-sm\">\n                {conditions.length} groups\n              </Badge>\n            </div>\n\n            {/* Mobile: Full width toolbar, Desktop: Compact */}\n            <div className=\"flex items-center justify-between sm:justify-end gap-1 sm:gap-2\">\n              {showToolbar && (\n                <>\n                  {enableHistory && (\n                    <div className=\"flex items-center gap-1\">\n                      <Button\n                        variant=\"ghost\"\n                        size=\"sm\"\n                        onClick={() => undo()}\n                        disabled={!canUndo() || readOnly}\n                        title=\"Undo\"\n                        className=\"h-8 w-8 p-0 sm:h-9 sm:w-9\"\n                      >\n                        <Undo2 className=\"h-3 w-3 sm:h-4 sm:w-4\" />\n                      </Button>\n                      <Button\n                        variant=\"ghost\"\n                        size=\"sm\"\n                        onClick={() => redo()}\n                        disabled={!canRedo() || readOnly}\n                        title=\"Redo\"\n                        className=\"h-8 w-8 p-0 sm:h-9 sm:w-9\"\n                      >\n                        <Redo2 className=\"h-3 w-3 sm:h-4 sm:w-4\" />\n                      </Button>\n                      <Separator\n                        orientation=\"vertical\"\n                        className=\"h-4 sm:h-6 mx-1\"\n                      />\n                    </div>\n                  )}\n\n                  <div className=\"flex items-center gap-1\">\n                    {onSave && (\n                      <Button\n                        variant=\"ghost\"\n                        size=\"sm\"\n                        onClick={async () => {\n                          setIsSaving(true);\n                          try {\n                            await onSave(rule);\n                            toast.success(mergedLabels.saveSuccess);\n                          } catch {\n                            toast.error(\"Failed to save rule\");\n                          } finally {\n                            setIsSaving(false);\n                          }\n                        }}\n                        disabled={readOnly || isSaving}\n                        title=\"Save\"\n                        className=\"h-8 w-8 p-0 sm:h-9 sm:w-9\"\n                      >\n                        <Save\n                          className={cn(\n                            \"h-3 w-3 sm:h-4 sm:w-4\",\n                            isSaving && \"animate-pulse\",\n                          )}\n                        />\n                      </Button>\n                    )}\n                    {onExport && (\n                      <Button\n                        variant=\"ghost\"\n                        size=\"sm\"\n                        onClick={() => {\n                          onExport(rule, \"json\");\n                          toast.success(mergedLabels.exportSuccess);\n                        }}\n                        title=\"Export JSON\"\n                        className=\"h-8 w-8 p-0 sm:h-9 sm:w-9\"\n                      >\n                        <FileJson className=\"h-3 w-3 sm:h-4 sm:w-4\" />\n                      </Button>\n                    )}\n                    <Button\n                      variant=\"ghost\"\n                      size=\"sm\"\n                      title=\"Help\"\n                      className=\"h-8 w-8 p-0 sm:h-9 sm:w-9\"\n                    >\n                      <HelpCircle className=\"h-3 w-3 sm:h-4 sm:w-4\" />\n                    </Button>\n                  </div>\n                </>\n              )}\n              <div className=\"ml-2\">\n                <ThemeToggle />\n              </div>\n            </div>\n          </div>\n        </CardHeader>\n      </Card>\n\n      {/* Mobile-First Layout: Stack on mobile, side-by-side on desktop */}\n      <div className=\"flex flex-col lg:grid lg:grid-cols-3 gap-4\">\n        {/* Rule Builder Area - Full width on mobile */}\n        <div className=\"lg:col-span-2 space-y-3 sm:space-y-4 order-2 lg:order-1\">\n          <DndContext\n            sensors={sensors}\n            collisionDetection={closestCenter}\n            onDragStart={handleDragStart}\n            onDragEnd={handleDragEnd}\n          >\n            <SortableContext\n              items={conditions.map((_, i) => `condition-${i}`)}\n              strategy={verticalListSortingStrategy}\n            >\n              {conditions.length === 0 ? (\n                <Card className=\"border-dashed\">\n                  <CardContent className=\"py-8 sm:py-12 text-center px-4\">\n                    <p className=\"text-muted-foreground mb-4 text-sm sm:text-base\">\n                      {mergedLabels.noRules}\n                    </p>\n                    {!readOnly && (\n                      <div className=\"flex flex-col sm:flex-row justify-center gap-2 sm:gap-3\">\n                        <Button\n                          onClick={() => addRootConditionGroup(\"or\")}\n                          className=\"text-sm w-full sm:w-auto\"\n                        >\n                          <Plus className=\"h-3 w-3 sm:h-4 sm:w-4 mr-2\" />\n                          Add {mergedLabels.or} Group\n                        </Button>\n                        <Button\n                          onClick={() => addRootConditionGroup(\"and\")}\n                          variant=\"outline\"\n                          className=\"text-sm w-full sm:w-auto\"\n                        >\n                          <Plus className=\"h-3 w-3 sm:h-4 sm:w-4 mr-2\" />\n                          Add {mergedLabels.and} Group\n                        </Button>\n                      </div>\n                    )}\n                  </CardContent>\n                </Card>\n              ) : (\n                <>\n                  {conditions.map((condition, index) => (\n                    <DraggableConditionGroup\n                      key={`condition-${index}`}\n                      id={`condition-${index}`}\n                      condition={condition}\n                      depth={0}\n                      onUpdate={(updated) => updateCondition(index, updated)}\n                      onRemove={() => removeCondition(index)}\n                      onDuplicate={() => duplicateCondition(index)}\n                      onAddConstraint={() => addConstraint(index)}\n                      onAddGroup={() => addNestedGroup(index)}\n                      readOnly={readOnly}\n                    >\n                      {renderItems(\n                        condition.or || condition.and || condition.none || [],\n                        `condition-${index}`,\n                        0,\n                      )}\n                    </DraggableConditionGroup>\n                  ))}\n                  {!readOnly && (\n                    <Button\n                      onClick={() => addRootConditionGroup()}\n                      variant=\"outline\"\n                      className=\"w-full text-sm py-2 sm:py-3\"\n                    >\n                      <Plus className=\"h-3 w-3 sm:h-4 sm:w-4 mr-2\" />\n                      {mergedLabels.addGroup}\n                    </Button>\n                  )}\n                </>\n              )}\n            </SortableContext>\n\n            <DragOverlay>\n              {activeId ? (\n                <div className=\"opacity-50\">\n                  {/* Render the dragged item */}\n                </div>\n              ) : null}\n            </DragOverlay>\n          </DndContext>\n        </div>\n\n        {/* JSON Viewer - Show first on mobile, second on desktop */}\n        {showJsonViewer && (\n          <div className=\"lg:col-span-1 order-1 lg:order-2\">\n            <div className=\"lg:sticky lg:top-4\">\n              <JsonViewer\n                rule={rule}\n                onImport={(imported) => {\n                  if (onImport) {\n                    onImport(JSON.stringify(imported), \"json\");\n                  }\n                  updateConditions(imported.conditions);\n                  toast.success(mergedLabels.importSuccess);\n                }}\n                expanded={expandedJson}\n                onExpandedChange={setExpandedJson}\n              />\n            </div>\n          </div>\n        )}\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/OperatorSelector.tsx",
    "content": "import type { OperatorsType } from \"@usex/rule-engine\";\nimport type { OperatorSelectorProps } from \"../types\";\nimport { Search } from \"lucide-react\";\nimport React, { useState, useMemo, useEffect } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport {\n  operatorConfigs,\n  getOperatorsForFieldType,\n  getOperatorConfig,\n} from \"../utils/operators\";\nimport { Input } from \"./ui/input\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectLabel,\n  SelectItem,\n  SelectGroup,\n  SelectContent,\n  Select,\n} from \"./ui/select\";\n\ninterface ExtendedOperatorSelectorProps extends OperatorSelectorProps {\n  customOperators?: Record<string, any>;\n  fieldType?: string;\n}\n\nexport const OperatorSelector: React.FC<ExtendedOperatorSelectorProps> = ({\n  value,\n  onChange,\n  operators = operatorConfigs,\n  fieldType,\n  disabled = false,\n  className,\n  customOperators,\n}) => {\n  const [searchTerm, setSearchTerm] = useState(\"\");\n  const [open, setOpen] = useState(false);\n  const inputRef = React.useRef<HTMLInputElement>(null);\n\n  const availableOperators = React.useMemo(() => {\n    const fieldOperators = getOperatorsForFieldType(fieldType);\n    const baseOperators = operators.filter((op) =>\n      fieldOperators.some((fo) => fo.name === op.name),\n    );\n\n    // Add custom operators if provided\n    if (customOperators) {\n      const customOps = Object.entries(customOperators).map(\n        ([name, config]) => ({\n          name,\n          label: config.label || name,\n          category: config.category || \"Custom\",\n          ...config,\n        }),\n      );\n      return [...baseOperators, ...customOps];\n    }\n\n    return baseOperators;\n  }, [operators, fieldType, customOperators]);\n\n  // Filter operators based on search term\n  const filteredOperators = useMemo(() => {\n    if (!searchTerm) return availableOperators;\n\n    const search = searchTerm.toLowerCase();\n    return availableOperators.filter((operator) => {\n      const label = (operator.label || operator.name).toLowerCase();\n      const category = (operator.category || \"\").toLowerCase();\n      const description = (operator.description || \"\").toLowerCase();\n\n      return (\n        label.includes(search) ||\n        category.includes(search) ||\n        description.includes(search) ||\n        operator.name.toLowerCase().includes(search)\n      );\n    });\n  }, [availableOperators, searchTerm]);\n\n  const groupedOperators = React.useMemo(() => {\n    const groups: Record<string, typeof filteredOperators> = {};\n\n    filteredOperators.forEach((operator) => {\n      const category = operator.category || \"Other\";\n      if (!groups[category]) {\n        groups[category] = [];\n      }\n      groups[category].push(operator);\n    });\n\n    return groups;\n  }, [filteredOperators]);\n\n  const selectedOperator = getOperatorConfig(value);\n\n  const handleOpenChange = (newOpen: boolean) => {\n    setOpen(newOpen);\n    if (!newOpen) {\n      // Reset search when closing\n      setSearchTerm(\"\");\n    }\n  };\n\n  // Keep focus on search input when operators change\n  useEffect(() => {\n    if (open && inputRef.current) {\n      // Use a small timeout to ensure the input is rendered\n      const timeoutId = setTimeout(() => {\n        inputRef.current?.focus();\n      }, 0);\n      return () => clearTimeout(timeoutId);\n    }\n  }, [open, filteredOperators]);\n\n  const handleSelect = (newValue: string) => {\n    onChange(newValue as OperatorsType);\n    setSearchTerm(\"\");\n    setOpen(false);\n  };\n\n  return (\n    <Select\n      value={value}\n      onValueChange={handleSelect}\n      disabled={disabled}\n      open={open}\n      onOpenChange={handleOpenChange}\n    >\n      <SelectTrigger className={cn(\"min-w-[200px]\", className)}>\n        <SelectValue placeholder=\"Select operator\">\n          {selectedOperator?.label || value}\n        </SelectValue>\n      </SelectTrigger>\n      <SelectContent>\n        {/* Search Input */}\n        <div className=\"p-2 border-b\">\n          <div className=\"relative\">\n            <Search className=\"absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n            <Input\n              ref={inputRef}\n              placeholder=\"Search operators...\"\n              value={searchTerm}\n              onChange={(e) => setSearchTerm(e.target.value)}\n              className=\"pl-8 h-8\"\n              autoFocus\n              onKeyDown={(e) => {\n                // Prevent the select from closing on space or enter in search\n                if (e.key === \" \" || e.key === \"Enter\") {\n                  e.stopPropagation();\n                }\n              }}\n            />\n          </div>\n        </div>\n\n        {/* Operator Groups */}\n        <div className=\"max-h-[300px] overflow-y-auto\">\n          {Object.entries(groupedOperators).length === 0 ? (\n            <div className=\"p-4 text-center text-sm text-muted-foreground\">\n              No operators found matching \"{searchTerm}\"\n            </div>\n          ) : (\n            Object.entries(groupedOperators).map(([category, ops]) => (\n              <SelectGroup key={category}>\n                <SelectLabel className=\"text-xs font-medium text-muted-foreground\">\n                  {category} ({ops.length})\n                </SelectLabel>\n                {ops.map((operator) => (\n                  <SelectItem\n                    key={operator.name}\n                    value={operator.name}\n                    className=\"cursor-pointer\"\n                  >\n                    <div className=\"flex flex-col py-1\">\n                      <span className=\"font-medium\">\n                        {operator.label || operator.name}\n                      </span>\n                      {operator.description && (\n                        <span className=\"text-xs text-muted-foreground line-clamp-1\">\n                          {operator.description}\n                        </span>\n                      )}\n                      {searchTerm && (\n                        <span className=\"text-xs text-primary/60\">\n                          {operator.name}\n                        </span>\n                      )}\n                    </div>\n                  </SelectItem>\n                ))}\n              </SelectGroup>\n            ))\n          )}\n        </div>\n\n        {/* Results count */}\n        {searchTerm && (\n          <div className=\"p-2 border-t text-xs text-center text-muted-foreground\">\n            {filteredOperators.length} of {availableOperators.length} operators\n          </div>\n        )}\n      </SelectContent>\n    </Select>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/RegexValidator.tsx",
    "content": "import { Regex, Info, Copy, CheckCircle2, AlertCircle } from \"lucide-react\";\nimport React, { useState, useMemo, useEffect } from \"react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"../lib/utils\";\nimport { AlertDescription, Alert } from \"./ui/alert\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Input } from \"./ui/input\";\nimport { Label } from \"./ui/label\";\nimport { ScrollArea } from \"./ui/scroll-area\";\nimport { Separator } from \"./ui/separator\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"./ui/tooltip\";\n\ninterface RegexValidatorProps {\n  value: string;\n  onChange: (value: string) => void;\n  testString?: string;\n  onTestStringChange?: (value: string) => void;\n  showVisualizer?: boolean;\n  className?: string;\n}\n\ninterface RegexMatch {\n  index: number;\n  value: string;\n  groups?: Record<string, string>;\n}\n\nconst commonPatterns = [\n  {\n    name: \"Email\",\n    pattern: \"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$\",\n  },\n  {\n    name: \"URL\",\n    pattern:\n      \"^https?:\\\\/\\\\/(www\\\\.)?[-a-zA-Z0-9@:%._\\\\+~#=]{1,256}\\\\.[a-zA-Z0-9()]{1,6}\\\\b([-a-zA-Z0-9()@:%_\\\\+.~#?&\\\\/\\\\/=]*)$\",\n  },\n  {\n    name: \"Phone (US)\",\n    pattern: \"^\\\\+?1?\\\\s?\\\\(?\\\\d{3}\\\\)?[\\\\s.-]?\\\\d{3}[\\\\s.-]?\\\\d{4}$\",\n  },\n  {\n    name: \"Phone (IR)\",\n    pattern: \"^(\\\\+98|98|0098|0)?9(\\\\d{2})\\\\d{7}$\",\n  },\n  {\n    name: \"Bank Card Number (IR)\",\n    pattern: \"([۰-۹0-9-_.*]{16,20})\",\n  },\n  {\n    name: \"Date (YYYY-MM-DD)\",\n    pattern: \"^\\\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\\\d|3[01])$\",\n  },\n  { name: \"Time (HH:MM)\", pattern: \"^([01]?[0-9]|2[0-3]):[0-5][0-9]$\" },\n  { name: \"IPv4\", pattern: \"^((25[0-5]|(2[0-4]|1\\\\d|[1-9]|)\\\\d)\\\\.?\\\\b){4}$\" },\n  { name: \"Hex Color\", pattern: \"^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$\" },\n  { name: \"Username\", pattern: \"^[a-zA-Z0-9_]{3,16}$\" },\n  {\n    name: \"Password (Strong)\",\n    pattern:\n      \"^(?=.*[a-z])(?=.*[A-Z])(?=.*\\\\d)(?=.*[@$!%*?&])[A-Za-z\\\\d@$!%*?&]{8,}$\",\n  },\n  {\n    name: \"Credit Card\",\n    pattern: \"^\\\\d{4}[\\\\s-]?\\\\d{4}[\\\\s-]?\\\\d{4}[\\\\s-]?\\\\d{4}$\",\n  },\n];\n\nconst regexFlags = [\n  {\n    flag: \"i\",\n    name: \"Case Insensitive\",\n    description: \"Match regardless of case\",\n  },\n  { flag: \"g\", name: \"Global\", description: \"Find all matches\" },\n  {\n    flag: \"m\",\n    name: \"Multiline\",\n    description: \"^ and $ match line boundaries\",\n  },\n  { flag: \"s\", name: \"Dot All\", description: \". matches newlines\" },\n  { flag: \"u\", name: \"Unicode\", description: \"Enable unicode support\" },\n];\n\nexport const RegexValidator: React.FC<RegexValidatorProps> = ({\n  value,\n  onChange,\n  testString = \"\",\n  onTestStringChange,\n  showVisualizer = true,\n  className,\n}) => {\n  const [localTestString, setLocalTestString] = useState(testString);\n  const [flags, setFlags] = useState(\"\");\n  const [regexError, setRegexError] = useState<string | null>(null);\n  const [matches, setMatches] = useState<RegexMatch[]>([]);\n\n  // Extract flags from the regex pattern if it's in /pattern/flags format\n  useEffect(() => {\n    const match = value.match(/^\\/(.*)\\/([gimsu]*)$/);\n    if (match) {\n      setFlags(match[2] || \"\");\n    }\n  }, [value]);\n\n  // Create regex object and validate\n  const regex = useMemo(() => {\n    try {\n      // Check if it's in /pattern/flags format\n      const match = value.match(/^\\/(.*)\\/([gimsu]*)$/);\n      if (match) {\n        return new RegExp(match[1], match[2]);\n      }\n      // Otherwise treat as a plain pattern\n      return new RegExp(value, flags);\n    } catch (error) {\n      setRegexError(error instanceof Error ? error.message : \"Invalid regex\");\n      return null;\n    }\n  }, [value, flags]);\n\n  // Test the regex against the test string\n  useEffect(() => {\n    if (!regex || !localTestString) {\n      setMatches([]);\n      return;\n    }\n\n    setRegexError(null);\n    const foundMatches: RegexMatch[] = [];\n\n    try {\n      if (regex.global) {\n        let match;\n        while ((match = regex.exec(localTestString)) !== null) {\n          foundMatches.push({\n            index: match.index,\n            value: match[0],\n            groups: match.groups,\n          });\n        }\n      } else {\n        const match = regex.exec(localTestString);\n        if (match) {\n          foundMatches.push({\n            index: match.index,\n            value: match[0],\n            groups: match.groups,\n          });\n        }\n      }\n      setMatches(foundMatches);\n    } catch (error) {\n      setRegexError(\n        error instanceof Error ? error.message : \"Error testing regex\",\n      );\n    }\n  }, [regex, localTestString]);\n\n  const handleFlagToggle = (flag: string) => {\n    if (flags.includes(flag)) {\n      setFlags(flags.replace(flag, \"\"));\n    } else {\n      setFlags(flags + flag);\n    }\n  };\n\n  const handlePatternSelect = (pattern: string) => {\n    onChange(pattern);\n    toast.success(\"Pattern applied\");\n  };\n\n  const handleCopyPattern = async (pattern: string) => {\n    try {\n      await navigator.clipboard.writeText(pattern);\n      toast.success(\"Pattern copied to clipboard\");\n    } catch {\n      toast.error(\"Failed to copy pattern\");\n    }\n  };\n\n  return (\n    <Card className={cn(\"overflow-hidden\", className)}>\n      <CardHeader className=\"pb-3\">\n        <div className=\"flex items-center justify-between\">\n          <div className=\"flex items-center gap-2\">\n            <Regex className=\"h-4 w-4 text-muted-foreground\" />\n            <CardTitle className=\"text-base\">Regex Validator</CardTitle>\n          </div>\n          {regex && !regexError && (\n            <Badge variant=\"outline\" className=\"text-green-600\">\n              <CheckCircle2 className=\"h-3 w-3 mr-1\" />\n              Valid\n            </Badge>\n          )}\n          {regexError && (\n            <Badge variant=\"outline\" className=\"text-destructive\">\n              <AlertCircle className=\"h-3 w-3 mr-1\" />\n              Invalid\n            </Badge>\n          )}\n        </div>\n      </CardHeader>\n      <CardContent className=\"space-y-4\">\n        {/* Regex Input */}\n        <div className=\"space-y-2\">\n          <Label>Regular Expression</Label>\n          <Input\n            value={value}\n            onChange={(e) => onChange(e.target.value)}\n            placeholder=\"Enter regex pattern...\"\n            className={cn(\n              \"font-mono text-sm\",\n              regexError && \"border-destructive\",\n            )}\n          />\n          {regexError && (\n            <p className=\"text-xs text-destructive\">{regexError}</p>\n          )}\n        </div>\n\n        {/* Flags */}\n        <div className=\"space-y-2\">\n          <Label>Flags</Label>\n          <div className=\"flex flex-wrap gap-2\">\n            {regexFlags.map((flagInfo) => (\n              <TooltipProvider key={flagInfo.flag}>\n                <Tooltip>\n                  <TooltipTrigger asChild>\n                    <Button\n                      variant={\n                        flags.includes(flagInfo.flag) ? \"default\" : \"outline\"\n                      }\n                      size=\"sm\"\n                      onClick={() => handleFlagToggle(flagInfo.flag)}\n                      className=\"h-7 px-2\"\n                    >\n                      {flagInfo.flag}\n                    </Button>\n                  </TooltipTrigger>\n                  <TooltipContent>\n                    <p className=\"font-medium\">{flagInfo.name}</p>\n                    <p className=\"text-xs\">{flagInfo.description}</p>\n                  </TooltipContent>\n                </Tooltip>\n              </TooltipProvider>\n            ))}\n          </div>\n        </div>\n\n        {/* Test String */}\n        <div className=\"space-y-2\">\n          <Label>Test String</Label>\n          <Input\n            value={localTestString}\n            onChange={(e) => {\n              setLocalTestString(e.target.value);\n              onTestStringChange?.(e.target.value);\n            }}\n            placeholder=\"Enter text to test against...\"\n            className=\"font-mono text-sm\"\n          />\n        </div>\n\n        {/* Matches */}\n        {localTestString && (\n          <div className=\"space-y-2\">\n            <div className=\"flex items-center justify-between\">\n              <Label>Matches</Label>\n              <Badge variant=\"secondary\">\n                {matches.length} {matches.length === 1 ? \"match\" : \"matches\"}\n              </Badge>\n            </div>\n            {matches.length > 0 ? (\n              <ScrollArea className=\"h-[100px] w-full rounded-md border p-2\">\n                <div className=\"space-y-1\">\n                  {matches.map((match) => (\n                    <div\n                      key={`${match.index}-${match.value}`}\n                      className=\"flex items-center justify-between text-sm\"\n                    >\n                      <code className=\"px-2 py-1 bg-muted rounded\">\n                        {match.value}\n                      </code>\n                      <span className=\"text-xs text-muted-foreground\">\n                        Index: {match.index}\n                      </span>\n                    </div>\n                  ))}\n                </div>\n              </ScrollArea>\n            ) : (\n              <Alert>\n                <AlertCircle className=\"h-4 w-4\" />\n                <AlertDescription>\n                  No matches found in the test string\n                </AlertDescription>\n              </Alert>\n            )}\n          </div>\n        )}\n\n        {/* Visual Representation */}\n        {showVisualizer && localTestString && regex && !regexError && (\n          <>\n            <Separator />\n            <div className=\"space-y-2\">\n              <Label>Visual Representation</Label>\n              <div className=\"p-3 bg-muted/50 rounded-md font-mono text-sm break-all\">\n                {localTestString.split(\"\").map((char, index) => {\n                  const isPartOfMatch = matches.some(\n                    (match) =>\n                      index >= match.index &&\n                      index < match.index + match.value.length,\n                  );\n                  return (\n                    <span\n                      key={`char-${index}-${char}`}\n                      className={cn(\n                        isPartOfMatch &&\n                          \"bg-primary/20 text-primary font-semibold\",\n                      )}\n                    >\n                      {char}\n                    </span>\n                  );\n                })}\n              </div>\n            </div>\n          </>\n        )}\n\n        {/* Common Patterns */}\n        <Separator />\n        <div className=\"space-y-2\">\n          <div className=\"flex items-center gap-2\">\n            <Label>Common Patterns</Label>\n            <TooltipProvider>\n              <Tooltip>\n                <TooltipTrigger>\n                  <Info className=\"h-3 w-3 text-muted-foreground\" />\n                </TooltipTrigger>\n                <TooltipContent>\n                  <p>Click to use, or copy pattern</p>\n                </TooltipContent>\n              </Tooltip>\n            </TooltipProvider>\n          </div>\n          <ScrollArea className=\"h-[150px] w-full\">\n            <div className=\"space-y-1 pr-4\">\n              {commonPatterns.map((pattern) => (\n                <div\n                  key={pattern.name}\n                  className=\"flex items-center justify-between p-2 hover:bg-muted/50 rounded-md group\"\n                >\n                  <button\n                    type=\"button\"\n                    className=\"flex-1 text-left\"\n                    onClick={() => handlePatternSelect(pattern.pattern)}\n                  >\n                    <p className=\"text-sm font-medium\">{pattern.name}</p>\n                    <p className=\"text-xs text-muted-foreground font-mono truncate\">\n                      {pattern.pattern}\n                    </p>\n                  </button>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    className=\"h-7 w-7 opacity-0 group-hover:opacity-100\"\n                    onClick={() => handleCopyPattern(pattern.pattern)}\n                  >\n                    <Copy className=\"h-3 w-3\" />\n                  </Button>\n                </div>\n              ))}\n            </div>\n          </ScrollArea>\n        </div>\n      </CardContent>\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/ResizablePanel.tsx",
    "content": "import React, { useState, useRef, useEffect, useCallback } from \"react\";\nimport { cn } from \"../lib/utils\";\n\ninterface ResizablePanelProps {\n  defaultSize?: number;\n  minSize?: number;\n  maxSize?: number;\n  direction?: \"horizontal\" | \"vertical\";\n  onResize?: (size: number) => void;\n  children: [React.ReactNode, React.ReactNode];\n  className?: string;\n  handleClassName?: string;\n  persistId?: string;\n}\n\nexport const ResizablePanel: React.FC<ResizablePanelProps> = ({\n  defaultSize = 40,\n  minSize = 20,\n  maxSize = 80,\n  direction = \"horizontal\",\n  onResize,\n  children,\n  className,\n  handleClassName,\n  persistId,\n}) => {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const [size, setSize] = useState(() => {\n    if (persistId) {\n      const saved = localStorage.getItem(`resizable-panel-${persistId}`);\n      return saved ? Number.parseFloat(saved) : defaultSize;\n    }\n    return defaultSize;\n  });\n  const [isDragging, setIsDragging] = useState(false);\n\n  const handleMouseDown = useCallback((e: React.MouseEvent) => {\n    e.preventDefault();\n    setIsDragging(true);\n  }, []);\n\n  const handleMouseMove = useCallback(\n    (e: MouseEvent) => {\n      if (!isDragging || !containerRef.current) return;\n\n      const container = containerRef.current;\n      const rect = container.getBoundingClientRect();\n\n      let newSize: number;\n      if (direction === \"horizontal\") {\n        const position = ((e.clientX - rect.left) / rect.width) * 100;\n        newSize = Math.max(minSize, Math.min(maxSize, position));\n      } else {\n        const position = ((e.clientY - rect.top) / rect.height) * 100;\n        newSize = Math.max(minSize, Math.min(maxSize, position));\n      }\n\n      setSize(newSize);\n      onResize?.(newSize);\n\n      if (persistId) {\n        localStorage.setItem(\n          `resizable-panel-${persistId}`,\n          newSize.toString(),\n        );\n      }\n    },\n    [isDragging, direction, minSize, maxSize, onResize, persistId],\n  );\n\n  const handleMouseUp = useCallback(() => {\n    setIsDragging(false);\n  }, []);\n\n  useEffect(() => {\n    if (isDragging) {\n      document.addEventListener(\"mousemove\", handleMouseMove);\n      document.addEventListener(\"mouseup\", handleMouseUp);\n      document.body.style.cursor =\n        direction === \"horizontal\" ? \"col-resize\" : \"row-resize\";\n      document.body.style.userSelect = \"none\";\n\n      return () => {\n        document.removeEventListener(\"mousemove\", handleMouseMove);\n        document.removeEventListener(\"mouseup\", handleMouseUp);\n        document.body.style.cursor = \"\";\n        document.body.style.userSelect = \"\";\n      };\n    }\n  }, [isDragging, handleMouseMove, handleMouseUp, direction]);\n\n  const isHorizontal = direction === \"horizontal\";\n\n  return (\n    <div\n      ref={containerRef}\n      className={cn(\n        \"relative flex h-full w-full\",\n        isHorizontal ? \"flex-row\" : \"flex-col\",\n        className,\n      )}\n    >\n      {/* First Panel */}\n      <div\n        className={cn(\"overflow-hidden\", isHorizontal ? \"h-full\" : \"w-full\")}\n        style={{\n          [isHorizontal ? \"width\" : \"height\"]: `${size}%`,\n        }}\n      >\n        {children[0]}\n      </div>\n\n      {/* Resize Handle */}\n      <div\n        onMouseDown={handleMouseDown}\n        className={cn(\n          \"relative group flex items-center justify-center\",\n          isHorizontal ? \"w-1 cursor-col-resize\" : \"h-1 cursor-row-resize\",\n          \"hover:bg-primary/10 transition-colors\",\n          isDragging && \"bg-primary/20\",\n          handleClassName,\n        )}\n      >\n        {/* Visual indicator */}\n        <div\n          className={cn(\n            \"absolute rounded-full bg-border transition-all\",\n            \"group-hover:bg-primary/50\",\n            isDragging && \"bg-primary\",\n            isHorizontal\n              ? \"h-8 w-1 group-hover:w-1.5\"\n              : \"w-8 h-1 group-hover:h-1.5\",\n          )}\n        />\n\n        {/* Draggable area */}\n        <div\n          className={cn(\n            \"absolute\",\n            isHorizontal ? \"inset-y-0 -inset-x-1\" : \"inset-x-0 -inset-y-1\",\n          )}\n        />\n      </div>\n\n      {/* Second Panel */}\n      <div\n        className={cn(\n          \"flex-1 overflow-hidden\",\n          isHorizontal ? \"h-full\" : \"w-full\",\n        )}\n      >\n        {children[1]}\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/RuleImportModal.tsx",
    "content": "import React, { useState, useRef } from \"react\";\nimport { Button } from \"./ui/button\";\nimport { Label } from \"./ui/label\";\nimport { Textarea } from \"./ui/textarea\";\nimport { Input } from \"./ui/input\";\nimport {\n  DialogTrigger,\n  DialogTitle,\n  DialogHeader,\n  DialogDescription,\n  DialogContent,\n  Dialog,\n} from \"./ui/dialog\";\nimport {\n  Upload,\n  Import,\n  FileText,\n  CheckCircle2,\n  AlertTriangle,\n} from \"lucide-react\";\nimport type { RuleType } from \"@usex/rule-engine\";\n\ninterface RuleImportModalProps {\n  onImport: (rule: RuleType) => void;\n  className?: string;\n}\n\nexport const RuleImportModal: React.FC<RuleImportModalProps> = ({\n  onImport,\n  className,\n}) => {\n  const [open, setOpen] = useState(false);\n  const [jsonText, setJsonText] = useState(\"\");\n  const [error, setError] = useState<string | null>(null);\n  const [success, setSuccess] = useState(false);\n  const fileInputRef = useRef<HTMLInputElement>(null);\n  const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n  // Auto-resize textarea\n  const adjustTextareaHeight = () => {\n    const textarea = textareaRef.current;\n    if (textarea) {\n      textarea.style.height = \"auto\";\n      textarea.style.height = `${Math.max(textarea.scrollHeight, 120)}px`;\n    }\n  };\n\n  const validateAndImportJson = (jsonString: string) => {\n    setError(null);\n    setSuccess(false);\n\n    if (!jsonString.trim()) {\n      setError(\"Please enter a JSON rule\");\n      return;\n    }\n\n    try {\n      const rule: RuleType = JSON.parse(jsonString);\n\n      // Basic validation\n      if (!rule.conditions) {\n        throw new Error(\"Rule must have a 'conditions' property\");\n      }\n\n      // Additional validation for the conditions structure\n      const condition = rule.conditions;\n      if (typeof condition !== \"object\" || condition === null) {\n        throw new Error(\"Conditions must be an object\");\n      }\n\n      const hasValidStructure =\n        (\"and\" in condition && Array.isArray(condition.and)) ||\n        (\"or\" in condition && Array.isArray(condition.or)) ||\n        (\"none\" in condition && Array.isArray(condition.none));\n\n      if (!hasValidStructure) {\n        throw new Error(\n          \"Conditions must have at least one of: 'and', 'or', or 'none' properties with array values\",\n        );\n      }\n\n      onImport(rule);\n      setSuccess(true);\n\n      // Clear after successful import and close modal\n      setTimeout(() => {\n        setJsonText(\"\");\n        setSuccess(false);\n        setError(null);\n        setOpen(false);\n        adjustTextareaHeight();\n      }, 1500);\n    } catch (err) {\n      setError(err instanceof Error ? err.message : \"Invalid JSON format\");\n    }\n  };\n\n  const handleTextareaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n    setJsonText(e.target.value);\n    setError(null);\n    setSuccess(false);\n    adjustTextareaHeight();\n  };\n\n  const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const file = e.target.files?.[0];\n    if (!file) return;\n\n    if (!file.name.endsWith(\".json\")) {\n      setError(\"Please select a JSON file (.json)\");\n      return;\n    }\n\n    const reader = new FileReader();\n    reader.onload = (event) => {\n      const content = event.target?.result as string;\n      setJsonText(content);\n      adjustTextareaHeight();\n      validateAndImportJson(content);\n    };\n\n    reader.onerror = () => {\n      setError(\"Failed to read file\");\n    };\n\n    reader.readAsText(file);\n\n    // Clear the input so the same file can be selected again\n    e.target.value = \"\";\n  };\n\n  const handleImportFromTextarea = () => {\n    validateAndImportJson(jsonText);\n  };\n\n  const handleClear = () => {\n    setJsonText(\"\");\n    setError(null);\n    setSuccess(false);\n    adjustTextareaHeight();\n  };\n\n  const handleOpenChange = (newOpen: boolean) => {\n    setOpen(newOpen);\n    if (!newOpen) {\n      // Reset state when closing\n      setJsonText(\"\");\n      setError(null);\n      setSuccess(false);\n    }\n  };\n\n  React.useEffect(() => {\n    if (open) {\n      adjustTextareaHeight();\n    }\n  }, [open]);\n\n  const sampleJson = `{\n  \"conditions\": {\n    \"and\": [\n      {\n        \"field\": \"user.age\",\n        \"operator\": \"greater_than\",\n        \"value\": 18\n      },\n      {\n        \"field\": \"user.status\",\n        \"operator\": \"equals\",\n        \"value\": \"active\"\n      }\n    ]\n  }\n}`;\n\n  return (\n    <Dialog open={open} onOpenChange={handleOpenChange}>\n      <DialogTrigger asChild>\n        <Button variant=\"outline\" className={className}>\n          <Import className=\"h-4 w-4 mr-2\" />\n          Import Rule JSON\n        </Button>\n      </DialogTrigger>\n      <DialogContent className=\"max-w-2xl max-h-[80vh] overflow-y-auto\">\n        <DialogHeader>\n          <DialogTitle className=\"flex items-center gap-2 text-gray-900 dark:text-white\">\n            <FileText className=\"h-5 w-5\" />\n            Import Rule JSON\n          </DialogTitle>\n          <DialogDescription className=\"text-gray-600 dark:text-gray-400\">\n            Import a rule by uploading a JSON file or pasting JSON directly\n          </DialogDescription>\n        </DialogHeader>\n\n        <div className=\"space-y-6 py-4\">\n          {/* File Upload Section */}\n          <div className=\"space-y-2\">\n            <Label\n              htmlFor=\"file-upload\"\n              className=\"text-gray-700 dark:text-gray-300\"\n            >\n              Upload JSON File\n            </Label>\n            <div className=\"flex items-center gap-2\">\n              <Input\n                ref={fileInputRef}\n                id=\"file-upload\"\n                type=\"file\"\n                accept=\".json\"\n                onChange={handleFileUpload}\n                className=\"hidden\"\n              />\n              <Button\n                type=\"button\"\n                variant=\"outline\"\n                onClick={() => fileInputRef.current?.click()}\n                className=\"flex items-center gap-2\"\n              >\n                <Upload className=\"h-4 w-4\" />\n                Choose JSON File\n              </Button>\n              <span className=\"text-sm text-gray-500 dark:text-gray-400\">\n                Select a .json file from your computer\n              </span>\n            </div>\n          </div>\n\n          {/* Text Area Section */}\n          <div className=\"space-y-2\">\n            <div className=\"flex items-center justify-between\">\n              <Label\n                htmlFor=\"json-textarea\"\n                className=\"text-gray-700 dark:text-gray-300\"\n              >\n                Or Paste JSON\n              </Label>\n              <Button\n                type=\"button\"\n                variant=\"ghost\"\n                size=\"sm\"\n                onClick={() => setJsonText(sampleJson)}\n                className=\"text-xs\"\n              >\n                Insert Sample\n              </Button>\n            </div>\n            <Textarea\n              ref={textareaRef}\n              id=\"json-textarea\"\n              value={jsonText}\n              onChange={handleTextareaChange}\n              placeholder=\"Paste your rule JSON here...\"\n              className=\"min-h-[120px] font-mono text-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 border-gray-300 dark:border-gray-600\"\n              style={{ resize: \"none\" }}\n            />\n            <div className=\"flex justify-between items-center\">\n              <div className=\"flex items-center gap-2\">\n                {error && (\n                  <div className=\"flex items-center gap-1 text-red-600 dark:text-red-400\">\n                    <AlertTriangle className=\"h-4 w-4\" />\n                    <span className=\"text-sm\">{error}</span>\n                  </div>\n                )}\n                {success && (\n                  <div className=\"flex items-center gap-1 text-green-600 dark:text-green-400\">\n                    <CheckCircle2 className=\"h-4 w-4\" />\n                    <span className=\"text-sm\">Rule imported successfully!</span>\n                  </div>\n                )}\n              </div>\n              <div className=\"flex gap-2\">\n                {jsonText && (\n                  <Button\n                    type=\"button\"\n                    variant=\"ghost\"\n                    size=\"sm\"\n                    onClick={handleClear}\n                  >\n                    Clear\n                  </Button>\n                )}\n                <Button\n                  type=\"button\"\n                  onClick={handleImportFromTextarea}\n                  disabled={!jsonText.trim()}\n                  size=\"sm\"\n                >\n                  Import JSON\n                </Button>\n              </div>\n            </div>\n          </div>\n\n          {/* Sample JSON Display */}\n          <div className=\"space-y-2\">\n            <Label className=\"text-gray-700 dark:text-gray-300\">\n              Expected JSON Format\n            </Label>\n            <pre className=\"bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100 p-3 rounded text-xs overflow-x-auto border border-gray-200 dark:border-gray-600\">\n              {sampleJson}\n            </pre>\n          </div>\n        </div>\n      </DialogContent>\n    </Dialog>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/RuleImporter.tsx",
    "content": "import React, { useState, useRef } from \"react\";\nimport { Button } from \"./ui/button\";\nimport { Label } from \"./ui/label\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Textarea } from \"./ui/textarea\";\nimport { Input } from \"./ui/input\";\nimport { Upload, FileText, CheckCircle2, AlertTriangle } from \"lucide-react\";\nimport type { RuleType } from \"@usex/rule-engine\";\nimport { cn } from \"../lib/utils\";\n\ninterface RuleImporterProps {\n  onImport: (rule: RuleType) => void;\n  className?: string;\n}\n\nexport const RuleImporter: React.FC<RuleImporterProps> = ({\n  onImport,\n  className,\n}) => {\n  const [jsonText, setJsonText] = useState(\"\");\n  const [error, setError] = useState<string | null>(null);\n  const [success, setSuccess] = useState(false);\n  const fileInputRef = useRef<HTMLInputElement>(null);\n  const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n  // Auto-resize textarea\n  const adjustTextareaHeight = () => {\n    const textarea = textareaRef.current;\n    if (textarea) {\n      textarea.style.height = \"auto\";\n      textarea.style.height = `${Math.max(textarea.scrollHeight, 120)}px`;\n    }\n  };\n\n  const validateAndImportJson = (jsonString: string) => {\n    setError(null);\n    setSuccess(false);\n\n    if (!jsonString.trim()) {\n      setError(\"Please enter a JSON rule\");\n      return;\n    }\n\n    try {\n      const rule: RuleType = JSON.parse(jsonString);\n\n      // Basic validation\n      if (!rule.conditions) {\n        throw new Error(\"Rule must have a 'conditions' property\");\n      }\n\n      // Additional validation for the conditions structure\n      const condition = rule.conditions;\n      if (typeof condition !== \"object\" || condition === null) {\n        throw new Error(\"Conditions must be an object\");\n      }\n\n      const hasValidStructure =\n        (\"and\" in condition && Array.isArray(condition.and)) ||\n        (\"or\" in condition && Array.isArray(condition.or)) ||\n        (\"none\" in condition && Array.isArray(condition.none));\n\n      if (!hasValidStructure) {\n        throw new Error(\n          \"Conditions must have at least one of: 'and', 'or', or 'none' properties with array values\",\n        );\n      }\n\n      onImport(rule);\n      setSuccess(true);\n\n      // Clear after successful import\n      setTimeout(() => {\n        setJsonText(\"\");\n        setSuccess(false);\n        adjustTextareaHeight();\n      }, 2000);\n    } catch (err) {\n      setError(err instanceof Error ? err.message : \"Invalid JSON format\");\n    }\n  };\n\n  const handleTextareaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n    setJsonText(e.target.value);\n    setError(null);\n    setSuccess(false);\n    adjustTextareaHeight();\n  };\n\n  const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const file = e.target.files?.[0];\n    if (!file) return;\n\n    if (!file.name.endsWith(\".json\")) {\n      setError(\"Please select a JSON file (.json)\");\n      return;\n    }\n\n    const reader = new FileReader();\n    reader.onload = (event) => {\n      const content = event.target?.result as string;\n      setJsonText(content);\n      adjustTextareaHeight();\n      validateAndImportJson(content);\n    };\n\n    reader.onerror = () => {\n      setError(\"Failed to read file\");\n    };\n\n    reader.readAsText(file);\n\n    // Clear the input so the same file can be selected again\n    e.target.value = \"\";\n  };\n\n  const handleImportFromTextarea = () => {\n    validateAndImportJson(jsonText);\n  };\n\n  const handleClear = () => {\n    setJsonText(\"\");\n    setError(null);\n    setSuccess(false);\n    adjustTextareaHeight();\n  };\n\n  React.useEffect(() => {\n    adjustTextareaHeight();\n  }, []);\n\n  const sampleJson = `{\n  \"conditions\": {\n    \"and\": [\n      {\n        \"field\": \"user.age\",\n        \"operator\": \"greater_than\",\n        \"value\": 18\n      },\n      {\n        \"field\": \"user.status\",\n        \"operator\": \"equals\",\n        \"value\": \"active\"\n      }\n    ]\n  }\n}`;\n\n  return (\n    <Card className={cn(\"w-full\", className)}>\n      <CardHeader>\n        <CardTitle className=\"flex items-center gap-2 text-gray-900 dark:text-white\">\n          <FileText className=\"h-5 w-5\" />\n          Import Rule JSON\n        </CardTitle>\n      </CardHeader>\n      <CardContent className=\"space-y-6\">\n        {/* File Upload Section */}\n        <div className=\"space-y-2\">\n          <Label\n            htmlFor=\"file-upload\"\n            className=\"text-gray-700 dark:text-gray-300\"\n          >\n            Upload JSON File\n          </Label>\n          <div className=\"flex items-center gap-2\">\n            <Input\n              ref={fileInputRef}\n              id=\"file-upload\"\n              type=\"file\"\n              accept=\".json\"\n              onChange={handleFileUpload}\n              className=\"hidden\"\n            />\n            <Button\n              type=\"button\"\n              variant=\"outline\"\n              onClick={() => fileInputRef.current?.click()}\n              className=\"flex items-center gap-2\"\n            >\n              <Upload className=\"h-4 w-4\" />\n              Choose JSON File\n            </Button>\n            <span className=\"text-sm text-gray-500 dark:text-gray-400\">\n              Select a .json file from your computer\n            </span>\n          </div>\n        </div>\n\n        {/* Text Area Section */}\n        <div className=\"space-y-2\">\n          <div className=\"flex items-center justify-between\">\n            <Label\n              htmlFor=\"json-textarea\"\n              className=\"text-gray-700 dark:text-gray-300\"\n            >\n              Or Paste JSON\n            </Label>\n            <Button\n              type=\"button\"\n              variant=\"ghost\"\n              size=\"sm\"\n              onClick={() => setJsonText(sampleJson)}\n              className=\"text-xs\"\n            >\n              Insert Sample\n            </Button>\n          </div>\n          <Textarea\n            ref={textareaRef}\n            id=\"json-textarea\"\n            value={jsonText}\n            onChange={handleTextareaChange}\n            placeholder=\"Paste your rule JSON here...\"\n            className=\"min-h-[120px] font-mono text-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 border-gray-300 dark:border-gray-600\"\n            style={{ resize: \"none\" }}\n          />\n          <div className=\"flex justify-between items-center\">\n            <div className=\"flex items-center gap-2\">\n              {error && (\n                <div className=\"flex items-center gap-1 text-red-600 dark:text-red-400\">\n                  <AlertTriangle className=\"h-4 w-4\" />\n                  <span className=\"text-sm\">{error}</span>\n                </div>\n              )}\n              {success && (\n                <div className=\"flex items-center gap-1 text-green-600 dark:text-green-400\">\n                  <CheckCircle2 className=\"h-4 w-4\" />\n                  <span className=\"text-sm\">Rule imported successfully!</span>\n                </div>\n              )}\n            </div>\n            <div className=\"flex gap-2\">\n              {jsonText && (\n                <Button\n                  type=\"button\"\n                  variant=\"ghost\"\n                  size=\"sm\"\n                  onClick={handleClear}\n                >\n                  Clear\n                </Button>\n              )}\n              <Button\n                type=\"button\"\n                onClick={handleImportFromTextarea}\n                disabled={!jsonText.trim()}\n                size=\"sm\"\n              >\n                Import JSON\n              </Button>\n            </div>\n          </div>\n        </div>\n\n        {/* Sample JSON Display */}\n        <div className=\"space-y-2\">\n          <Label className=\"text-gray-700 dark:text-gray-300\">\n            Expected JSON Format\n          </Label>\n          <pre className=\"bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100 p-3 rounded text-xs overflow-x-auto border border-gray-200 dark:border-gray-600\">\n            {sampleJson}\n          </pre>\n        </div>\n      </CardContent>\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/RuleViewer.tsx",
    "content": "import React from \"react\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Button } from \"./ui/button\";\nimport { Copy, ChevronRight, ChevronDown, Check } from \"lucide-react\";\nimport { JsonViewer } from \"./JsonVisualizer\";\nimport type { RuleViewerProps } from \"../types\";\nimport { cn } from \"../lib/utils\";\n\nexport const RuleViewer: React.FC<RuleViewerProps> = ({\n  rule,\n  className,\n  collapsible = true,\n  defaultCollapsed = false,\n}) => {\n  const [collapsed, setCollapsed] = React.useState(defaultCollapsed);\n  const [copied, setCopied] = React.useState(false);\n\n  const handleCopy = async () => {\n    try {\n      const jsonString = JSON.stringify(rule, null, 2);\n      await navigator.clipboard.writeText(jsonString);\n      setCopied(true);\n      setTimeout(() => setCopied(false), 2000);\n    } catch (error) {\n      console.error(\"Failed to copy:\", error);\n    }\n  };\n\n  return (\n    <Card className={cn(\"overflow-hidden\", className)}>\n      <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n        <div className=\"flex items-center gap-2\">\n          {collapsible && (\n            <Button\n              type=\"button\"\n              variant=\"ghost\"\n              size=\"sm\"\n              onClick={() => setCollapsed(!collapsed)}\n              className=\"p-0 h-auto\"\n            >\n              {collapsed ? (\n                <ChevronRight className=\"h-4 w-4\" />\n              ) : (\n                <ChevronDown className=\"h-4 w-4\" />\n              )}\n            </Button>\n          )}\n          <CardTitle className=\"text-sm font-medium text-gray-900 dark:text-white\">\n            Rule JSON\n          </CardTitle>\n        </div>\n        <Button\n          type=\"button\"\n          variant=\"ghost\"\n          size=\"sm\"\n          onClick={handleCopy}\n          className=\"h-8 px-2\"\n        >\n          {copied ? (\n            <>\n              <Check className=\"h-4 w-4 mr-2 text-green-600\" />\n              Copied\n            </>\n          ) : (\n            <>\n              <Copy className=\"h-4 w-4 mr-2\" />\n              Copy\n            </>\n          )}\n        </Button>\n      </CardHeader>\n      {!collapsed && (\n        <CardContent>\n          <div className=\"rounded-lg bg-gray-50 dark:bg-background p-4 border border-gray-200 dark:border-gray-700\">\n            <JsonViewer\n              data={rule}\n              rootName=\"rule\"\n              defaultExpanded={true}\n              highlightLogicalOperators={true}\n              className=\"text-gray-900 dark:text-gray-100\"\n            />\n          </div>\n        </CardContent>\n      )}\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/SmartOperatorSelector.tsx",
    "content": "import type { OperatorsType } from \"@usex/rule-engine\";\nimport type { OperatorSelectorProps } from \"../types\";\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport {\n  Zap,\n  Type,\n  TrendingUp,\n  ToggleRight,\n  Star,\n  Sparkles,\n  Search,\n  List,\n  Hash,\n  FileJson,\n  Clock,\n  ChevronRight,\n  Calendar,\n  Braces,\n} from \"lucide-react\";\nimport React, { useState, useMemo, useEffect } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport {\n  operatorConfigs,\n  getOperatorsForFieldType,\n  getOperatorConfig,\n} from \"../utils/operators\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { Input } from \"./ui/input\";\nimport { PopoverTrigger, PopoverContent, Popover } from \"./ui/popover\";\nimport { Separator } from \"./ui/separator\";\n\ninterface ExtendedOperatorSelectorProps extends OperatorSelectorProps {\n  customOperators?: Record<string, any>;\n  fieldType?: string;\n  fieldName?: string;\n}\n\nconst RECENT_OPERATORS_KEY = \"rule-builder-recent-operators\";\nconst OPERATOR_USAGE_KEY = \"rule-builder-operator-usage\";\nconst MAX_RECENT_OPERATORS = 5;\n\n// Smart operator recommendations based on field patterns\nconst SMART_RECOMMENDATIONS = [\n  {\n    fieldPattern: /age|year|count|quantity|amount|price|total/i,\n    operators: [\"greater-than\", \"less-than\", \"between\", \"equals\"],\n    reason: \"Numeric comparison\",\n  },\n  {\n    fieldPattern: /date|time|created|updated|expires/i,\n    operators: [\"date-after\", \"date-before\", \"date-between\", \"date-after-now\"],\n    reason: \"Date/time comparison\",\n  },\n  {\n    fieldPattern: /status|state|type|category|role/i,\n    operators: [\"equals\", \"not-equals\", \"in\", \"not-in\"],\n    reason: \"Categorical matching\",\n  },\n  {\n    fieldPattern: /email|url|id|code|key/i,\n    operators: [\"equals\", \"matches\", \"contains\", \"empty\"],\n    reason: \"String validation\",\n  },\n  {\n    fieldPattern: /active|enabled|verified|premium|default/i,\n    operators: [\"equals\", \"truthy\", \"falsy\"],\n    reason: \"Boolean check\",\n  },\n  {\n    fieldPattern: /items|tags|categories|benefits|permissions/i,\n    operators: [\"contains\", \"contains-all\", \"contains-any\", \"empty\"],\n    reason: \"Array operations\",\n  },\n  {\n    fieldPattern: /name|description|message|text|title/i,\n    operators: [\"contains\", \"matches\", \"empty\", \"not-empty\"],\n    reason: \"Text search\",\n  },\n];\n\nconst categoryOrder = [\n  \"recommended\",\n  \"recent\",\n  \"popular\",\n  \"comparison\",\n  \"validation\",\n  \"array\",\n  \"date\",\n  \"other\",\n];\n\nconst operatorIcons: Record<string, React.ElementType> = {\n  equals: Hash,\n  contains: Type,\n  \"greater-than\": TrendingUp,\n  \"less-than\": TrendingUp,\n  \"date-after\": Calendar,\n  \"date-before\": Calendar,\n  in: List,\n  matches: FileJson,\n  empty: Braces,\n  truthy: ToggleRight,\n  falsy: ToggleRight,\n};\n\nconst operatorColors: Record<string, string> = {\n  // Comparison\n  equals: \"text-blue-600 dark:text-blue-400\",\n  \"not-equals\": \"text-blue-600 dark:text-blue-400\",\n  \"greater-than\": \"text-green-600 dark:text-green-400\",\n  \"less-than\": \"text-green-600 dark:text-green-400\",\n  \"greater-than-or-equals\": \"text-green-600 dark:text-green-400\",\n  \"less-than-or-equals\": \"text-green-600 dark:text-green-400\",\n  between: \"text-green-600 dark:text-green-400\",\n  \"not-between\": \"text-green-600 dark:text-green-400\",\n\n  // String\n  contains: \"text-purple-600 dark:text-purple-400\",\n  \"not-contains\": \"text-purple-600 dark:text-purple-400\",\n  \"contains-any\": \"text-purple-600 dark:text-purple-400\",\n  \"contains-all\": \"text-purple-600 dark:text-purple-400\",\n  matches: \"text-indigo-600 dark:text-indigo-400\",\n  \"not-matches\": \"text-indigo-600 dark:text-indigo-400\",\n  like: \"text-purple-600 dark:text-purple-400\",\n  \"not-like\": \"text-purple-600 dark:text-purple-400\",\n\n  // Array\n  in: \"text-yellow-600 dark:text-yellow-400\",\n  \"not-in\": \"text-yellow-600 dark:text-yellow-400\",\n  \"self-contains-any\": \"text-yellow-600 dark:text-yellow-400\",\n  \"self-contains-all\": \"text-yellow-600 dark:text-yellow-400\",\n\n  // Date\n  \"date-after\": \"text-orange-600 dark:text-orange-400\",\n  \"date-before\": \"text-orange-600 dark:text-orange-400\",\n  \"date-between\": \"text-orange-600 dark:text-orange-400\",\n  \"date-equals\": \"text-orange-600 dark:text-orange-400\",\n  \"date-after-now\": \"text-orange-600 dark:text-orange-400\",\n  \"date-before-now\": \"text-orange-600 dark:text-orange-400\",\n\n  // Boolean\n  truthy: \"text-emerald-600 dark:text-emerald-400\",\n  falsy: \"text-red-600 dark:text-red-400\",\n  boolean: \"text-emerald-600 dark:text-emerald-400\",\n  \"not-boolean\": \"text-emerald-600 dark:text-emerald-400\",\n\n  // Existence\n  exists: \"text-teal-600 dark:text-teal-400\",\n  \"not-exists\": \"text-teal-600 dark:text-teal-400\",\n  empty: \"text-gray-600 dark:text-gray-400\",\n  \"not-empty\": \"text-gray-600 dark:text-gray-400\",\n  \"null-or-undefined\": \"text-gray-600 dark:text-gray-400\",\n  \"not-null-or-undefined\": \"text-gray-600 dark:text-gray-400\",\n};\n\nexport const SmartOperatorSelector: React.FC<ExtendedOperatorSelectorProps> = ({\n  value,\n  onChange,\n  operators = operatorConfigs,\n  fieldType,\n  fieldName,\n  disabled = false,\n  className,\n  customOperators,\n}) => {\n  const [open, setOpen] = useState(false);\n  const [search, setSearch] = useState(\"\");\n  const [recentOperators, setRecentOperators] = useState<string[]>([]);\n  const [operatorUsage, setOperatorUsage] = useState<Record<string, number>>(\n    {},\n  );\n  const inputRef = React.useRef<HTMLInputElement>(null);\n\n  // Load recent operators and usage stats\n  useEffect(() => {\n    const recent = localStorage.getItem(RECENT_OPERATORS_KEY);\n    if (recent) {\n      setRecentOperators(JSON.parse(recent));\n    }\n\n    const usage = localStorage.getItem(OPERATOR_USAGE_KEY);\n    if (usage) {\n      setOperatorUsage(JSON.parse(usage));\n    }\n  }, []);\n\n  // Get available operators for field type\n  const availableOperators = useMemo(() => {\n    const fieldOperators = getOperatorsForFieldType(fieldType);\n    const baseOperators = operators.filter((op) =>\n      fieldOperators.some((fo) => fo.name === op.name),\n    );\n\n    if (customOperators) {\n      const customOps = Object.entries(customOperators).map(\n        ([name, config]) => ({\n          name,\n          label: config.label || name,\n          category: config.category || \"Custom\",\n          ...config,\n        }),\n      );\n      return [...baseOperators, ...customOps];\n    }\n\n    return baseOperators;\n  }, [operators, fieldType, customOperators]);\n\n  // Get smart recommendations\n  const recommendations = useMemo(() => {\n    if (!fieldName) return [];\n\n    const recommended: typeof availableOperators = [];\n\n    SMART_RECOMMENDATIONS.forEach(\n      ({ fieldPattern, operators: recommendedOps, reason }) => {\n        if (fieldPattern.test(fieldName)) {\n          recommendedOps.forEach((opName) => {\n            const operator = availableOperators.find(\n              (op) => op.name === opName,\n            );\n            if (\n              operator &&\n              !recommended.find((r) => r.name === operator.name)\n            ) {\n              recommended.push({\n                ...operator,\n                category: \"recommended\",\n                description: reason,\n              });\n            }\n          });\n        }\n      },\n    );\n\n    return recommended;\n  }, [fieldName, availableOperators]);\n\n  // Filter operators based on search\n  const filteredOperators = useMemo(() => {\n    if (!search) {\n      return availableOperators;\n    }\n\n    const searchLower = search.toLowerCase();\n    return availableOperators.filter((operator) => {\n      const label = (operator.label || operator.name).toLowerCase();\n      const category = (operator.category || \"\").toLowerCase();\n      const description = (operator.description || \"\").toLowerCase();\n\n      return (\n        label.includes(searchLower) ||\n        category.includes(searchLower) ||\n        description.includes(searchLower) ||\n        operator.name.toLowerCase().includes(searchLower)\n      );\n    });\n  }, [availableOperators, search]);\n\n  // Group operators by category\n  const groupedOperators = useMemo(() => {\n    const groups: Record<string, typeof availableOperators> = {};\n\n    // Add recommendations first\n    if (recommendations.length > 0 && !search) {\n      groups.recommended = recommendations;\n    }\n\n    // Add recent operators\n    const recentOps = recentOperators\n      .map((opName) => availableOperators.find((op) => op.name === opName))\n      .filter(Boolean)\n      .slice(0, MAX_RECENT_OPERATORS);\n\n    if (recentOps.length > 0 && !search) {\n      groups.recent = recentOps as typeof availableOperators;\n    }\n\n    // Add popular operators (sorted by usage)\n    const popularOps = Object.entries(operatorUsage)\n      .sort(([, a], [, b]) => b - a)\n      .slice(0, 5)\n      .map(([opName]) => availableOperators.find((op) => op.name === opName))\n      .filter(Boolean);\n\n    if (popularOps.length > 0 && !search) {\n      groups.popular = popularOps as typeof availableOperators;\n    }\n\n    // Group remaining operators\n    filteredOperators.forEach((operator) => {\n      const category = operator.category || \"other\";\n      if (!groups[category]) {\n        groups[category] = [];\n      }\n\n      // Don't duplicate operators already in special groups\n      if (\n        !groups.recommended?.find((op) => op.name === operator.name) &&\n        !groups.recent?.find((op) => op.name === operator.name) &&\n        !groups.popular?.find((op) => op.name === operator.name)\n      ) {\n        groups[category].push(operator);\n      }\n    });\n\n    // Sort groups by predefined order\n    const sortedGroups: Record<string, typeof availableOperators> = {};\n    categoryOrder.forEach((cat) => {\n      if (groups[cat]) {\n        sortedGroups[cat] = groups[cat];\n      }\n    });\n\n    // Add any remaining categories\n    Object.keys(groups).forEach((cat) => {\n      if (!sortedGroups[cat]) {\n        sortedGroups[cat] = groups[cat];\n      }\n    });\n\n    return sortedGroups;\n  }, [\n    filteredOperators,\n    recommendations,\n    recentOperators,\n    operatorUsage,\n    availableOperators,\n    search,\n  ]);\n\n  const selectedOperator = getOperatorConfig(value);\n\n  const handleSelect = (operator: string) => {\n    onChange(operator as OperatorsType);\n    setSearch(\"\");\n    setOpen(false);\n\n    // Update recent operators\n    const newRecent = [\n      operator,\n      ...recentOperators.filter((op) => op !== operator),\n    ].slice(0, MAX_RECENT_OPERATORS);\n    setRecentOperators(newRecent);\n    localStorage.setItem(RECENT_OPERATORS_KEY, JSON.stringify(newRecent));\n\n    // Update usage statistics\n    const newUsage = { ...operatorUsage };\n    newUsage[operator] = (newUsage[operator] || 0) + 1;\n    setOperatorUsage(newUsage);\n    localStorage.setItem(OPERATOR_USAGE_KEY, JSON.stringify(newUsage));\n  };\n\n  // Keep focus on search input\n  useEffect(() => {\n    if (open && inputRef.current) {\n      const timeoutId = setTimeout(() => {\n        inputRef.current?.focus();\n      }, 0);\n      return () => clearTimeout(timeoutId);\n    }\n  }, [open, filteredOperators]);\n\n  const categoryIcons = {\n    recommended: Sparkles,\n    recent: Clock,\n    popular: TrendingUp,\n    comparison: TrendingUp,\n    validation: ToggleRight,\n    array: List,\n    date: Calendar,\n    other: FileJson,\n  };\n\n  const categoryLabels = {\n    recommended: \"AI Recommended\",\n    recent: \"Recently Used\",\n    popular: \"Most Popular\",\n    comparison: \"Comparison\",\n    validation: \"Validation\",\n    array: \"Array Operations\",\n    date: \"Date & Time\",\n    other: \"Other\",\n  };\n\n  return (\n    <Popover open={open} onOpenChange={setOpen}>\n      <PopoverTrigger asChild>\n        <Button\n          variant=\"outline\"\n          role=\"combobox\"\n          aria-expanded={open}\n          disabled={disabled}\n          className={cn(\"justify-between\", className)}\n        >\n          <div className=\"flex items-center gap-2\">\n            {selectedOperator &&\n              operatorIcons[selectedOperator.name] &&\n              React.createElement(operatorIcons[selectedOperator.name], {\n                className: cn(\"h-4 w-4\", operatorColors[selectedOperator.name]),\n              })}\n            <span>\n              {selectedOperator?.label || value || \"Select operator...\"}\n            </span>\n          </div>\n          <ChevronRight className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n        </Button>\n      </PopoverTrigger>\n\n      <PopoverContent className=\"w-[400px] p-0\" align=\"start\">\n        <CommandPrimitive className=\"overflow-hidden rounded-md border shadow-md\">\n          <div className=\"flex items-center border-b px-3 py-2\">\n            <Search className=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n            <Input\n              ref={inputRef}\n              value={search}\n              onChange={(e) => setSearch(e.target.value)}\n              placeholder=\"Search operators...\"\n              className=\"flex h-8 w-full rounded-md bg-transparent py-2 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 border-0 focus-visible:ring-0\"\n              autoFocus\n            />\n          </div>\n\n          <div className=\"max-h-[400px] overflow-y-auto\">\n            {Object.entries(groupedOperators).length === 0 ? (\n              <div className=\"py-6 text-center text-sm text-muted-foreground\">\n                No operators found\n              </div>\n            ) : (\n              Object.entries(groupedOperators).map(([category, ops]) => {\n                const CategoryIcon =\n                  categoryIcons[category as keyof typeof categoryIcons] ||\n                  FileJson;\n                const categoryLabel =\n                  categoryLabels[category as keyof typeof categoryLabels] ||\n                  category;\n\n                return (\n                  <div key={category} className=\"p-2\">\n                    <div className=\"mb-2 flex items-center gap-2 px-2 text-xs font-medium text-muted-foreground\">\n                      <CategoryIcon className=\"h-3 w-3\" />\n                      {categoryLabel}\n                      {category === \"recommended\" && (\n                        <Badge\n                          variant=\"secondary\"\n                          className=\"h-4 text-[10px] px-1\"\n                        >\n                          <Zap className=\"h-2 w-2 mr-0.5\" />\n                          AI\n                        </Badge>\n                      )}\n                    </div>\n\n                    {ops.map((operator) => {\n                      const isSelected = value === operator.name;\n                      const OperatorIcon =\n                        operatorIcons[operator.name] || FileJson;\n                      const usage = operatorUsage[operator.name];\n\n                      return (\n                        <button\n                          key={operator.name}\n                          onClick={() => handleSelect(operator.name)}\n                          className={cn(\n                            \"relative flex w-full items-center rounded-sm px-2 py-1.5 text-sm outline-none\",\n                            \"hover:bg-accent hover:text-accent-foreground\",\n                            \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n                            isSelected && \"bg-accent text-accent-foreground\",\n                            \"group\",\n                          )}\n                        >\n                          <OperatorIcon\n                            className={cn(\n                              \"mr-2 h-4 w-4\",\n                              operatorColors[operator.name],\n                            )}\n                          />\n                          <div className=\"flex-1 text-left\">\n                            <div className=\"flex items-center gap-2\">\n                              <span className=\"font-medium\">\n                                {operator.label || operator.name}\n                              </span>\n                              {usage && usage > 5 && (\n                                <Badge\n                                  variant=\"secondary\"\n                                  className=\"h-4 text-[10px] px-1\"\n                                >\n                                  {usage}x\n                                </Badge>\n                              )}\n                              {category === \"recommended\" && (\n                                <Badge\n                                  variant=\"outline\"\n                                  className=\"h-4 text-[10px] px-1\"\n                                >\n                                  {operator.description}\n                                </Badge>\n                              )}\n                            </div>\n                            {operator.description &&\n                              category !== \"recommended\" && (\n                                <div className=\"text-xs text-muted-foreground\">\n                                  {operator.description}\n                                </div>\n                              )}\n                          </div>\n                          {category === \"recent\" && (\n                            <Clock className=\"ml-2 h-3 w-3 text-muted-foreground opacity-0 group-hover:opacity-100\" />\n                          )}\n                          {category === \"popular\" && (\n                            <Star className=\"ml-2 h-3 w-3 text-yellow-500 opacity-0 group-hover:opacity-100\" />\n                          )}\n                        </button>\n                      );\n                    })}\n                  </div>\n                );\n              })\n            )}\n          </div>\n\n          {fieldName && recommendations.length > 0 && (\n            <>\n              <Separator />\n              <div className=\"p-2 text-xs text-muted-foreground\">\n                <div className=\"flex items-center gap-1\">\n                  <Sparkles className=\"h-3 w-3\" />\n                  AI suggestions based on field:{\" \"}\n                  <code className=\"bg-muted px-1 rounded\">{fieldName}</code>\n                </div>\n              </div>\n            </>\n          )}\n        </CommandPrimitive>\n      </PopoverContent>\n    </Popover>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/ThemeToggle.tsx",
    "content": "import React from \"react\";\nimport { Sun, Moon, Monitor } from \"lucide-react\";\nimport { Button } from \"./ui/button\";\nimport {\n  DropdownMenuTrigger,\n  DropdownMenuItem,\n  DropdownMenuContent,\n  DropdownMenu,\n} from \"./ui/dropdown-menu\";\nimport { useTheme } from \"../hooks/use-theme\";\n\nexport const ThemeToggle: React.FC = () => {\n  const { setTheme } = useTheme();\n\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger asChild>\n        <Button variant=\"ghost\" size=\"icon\" className=\"h-9 w-9\">\n          <Sun className=\"h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0\" />\n          <Moon className=\"absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100\" />\n          <span className=\"sr-only\">Toggle theme</span>\n        </Button>\n      </DropdownMenuTrigger>\n      <DropdownMenuContent align=\"end\">\n        <DropdownMenuItem onClick={() => setTheme(\"light\")}>\n          <Sun className=\"mr-2 h-4 w-4\" />\n          <span>Light</span>\n        </DropdownMenuItem>\n        <DropdownMenuItem onClick={() => setTheme(\"dark\")}>\n          <Moon className=\"mr-2 h-4 w-4\" />\n          <span>Dark</span>\n        </DropdownMenuItem>\n        <DropdownMenuItem onClick={() => setTheme(\"system\")}>\n          <Monitor className=\"mr-2 h-4 w-4\" />\n          <span>System</span>\n        </DropdownMenuItem>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/TreeConditionGroup.tsx",
    "content": "import type { Constraint, ConditionType, Condition } from \"@usex/rule-engine\";\nimport type { FieldConfig } from \"../types\";\nimport {\n  Trash2,\n  Plus,\n  Layers,\n  GitBranch,\n  Copy,\n  ChevronRight,\n  ChevronDown,\n} from \"lucide-react\";\nimport React from \"react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"../lib/utils\";\nimport { useEnhancedRuleStore } from \"../stores/enhanced-rule-store\";\nimport { TreeConstraintEditor } from \"./TreeConstraintEditor\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { Card } from \"./ui/card\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectItem,\n  SelectContent,\n  Select,\n} from \"./ui/select\";\n\ninterface TreeConditionGroupProps {\n  condition: Condition;\n  path: number[];\n  depth: number;\n  fields?: FieldConfig[];\n  sampleData?: Record<string, any>;\n  customOperators?: Record<string, any>;\n  maxNestingDepth?: number;\n  onUpdate: (condition: Condition) => void;\n  onRemove: () => void;\n  onDuplicate: () => void;\n  readOnly?: boolean;\n  labels?: {\n    or?: string;\n    and?: string;\n    none?: string;\n    addGroup?: string;\n    addRule?: string;\n    removeGroup?: string;\n    duplicateGroup?: string;\n  };\n  colors?: {\n    or?: string;\n    and?: string;\n    none?: string;\n  };\n}\n\nexport const TreeConditionGroup: React.FC<TreeConditionGroupProps> = ({\n  condition,\n  path,\n  depth,\n  fields = [],\n  sampleData,\n  customOperators,\n  maxNestingDepth = 10,\n  onUpdate,\n  onRemove,\n  onDuplicate,\n  readOnly = false,\n  labels = {},\n  colors = {},\n}) => {\n  const { isGroupExpanded, toggleGroupExpanded } = useEnhancedRuleStore();\n  const groupPath = path.join(\"-\");\n  const isExpanded = depth === 0 ? true : isGroupExpanded(groupPath);\n\n  const conditionType = Object.keys(condition).find(\n    (key) => key === \"or\" || key === \"and\" || key === \"none\",\n  ) as ConditionType;\n\n  const items = condition[conditionType] || [];\n\n  const isConstraint = (item: any): item is Constraint => {\n    return \"field\" in item && \"operator\" in item;\n  };\n\n  const typeColors = {\n    or: colors.or || \"border-blue-500/30 bg-blue-500/5 dark:bg-blue-500/10\",\n    and:\n      colors.and || \"border-green-500/30 bg-green-500/5 dark:bg-green-500/10\",\n    none: colors.none || \"border-red-500/30 bg-red-500/5 dark:bg-red-500/10\",\n  };\n\n  const typeLabels = {\n    or: labels.or || \"OR\",\n    and: labels.and || \"AND\",\n    none: labels.none || \"NONE\",\n  };\n\n  const handleTypeChange = (newType: ConditionType) => {\n    const newCondition = {\n      [newType]: items,\n    } as Condition;\n    onUpdate(newCondition);\n  };\n\n  const addConstraint = () => {\n    const newConstraint: Constraint = {\n      field: \"\",\n      operator: \"equals\" as any,\n      value: \"\",\n    };\n\n    const updatedItems = [...items, newConstraint];\n    onUpdate({ [conditionType]: updatedItems } as Condition);\n    toast.success(\"Added new rule\");\n  };\n\n  const addNestedGroup = () => {\n    if (depth >= maxNestingDepth) {\n      toast.error(`Maximum nesting depth (${maxNestingDepth}) reached`);\n      return;\n    }\n\n    const newCondition: Condition = { and: [] };\n    const updatedItems = [...items, newCondition];\n    onUpdate({ [conditionType]: updatedItems } as Condition);\n    toast.success(\"Added nested group\");\n  };\n\n  const updateItem = (index: number, updatedItem: Constraint | Condition) => {\n    const updatedItems = [...items];\n    updatedItems[index] = updatedItem;\n    onUpdate({ [conditionType]: updatedItems } as Condition);\n  };\n\n  const removeItem = (index: number) => {\n    const updatedItems = items.filter((_, i) => i !== index);\n    onUpdate({ [conditionType]: updatedItems } as Condition);\n    toast.success(\"Removed item\");\n  };\n\n  const duplicateItem = (index: number) => {\n    const itemToDuplicate = items[index];\n    const duplicated = JSON.parse(JSON.stringify(itemToDuplicate));\n    const updatedItems = [...items];\n    updatedItems.splice(index + 1, 0, duplicated);\n    onUpdate({ [conditionType]: updatedItems } as Condition);\n    toast.success(\"Duplicated item\");\n  };\n\n  // Calculate indentation based on depth\n  const indentClass = cn({\n    \"ml-0\": depth === 0,\n    \"ml-4\": depth === 1,\n    \"ml-8\": depth === 2,\n    \"ml-12\": depth === 3,\n    \"ml-16\": depth >= 4,\n  });\n\n  return (\n    <div\n      className={cn(\n        \"relative animate-in fade-in-0 slide-in-from-top-2 duration-300\",\n        indentClass,\n      )}\n    >\n      {/* Connection line for nested items */}\n      {depth > 0 && (\n        <div\n          className={cn(\n            \"absolute left-[-16px] top-0 bottom-0 w-px\",\n            conditionType === \"or\" && \"bg-blue-500/30\",\n            conditionType === \"and\" && \"bg-green-500/30\",\n            conditionType === \"none\" && \"bg-red-500/30\",\n          )}\n          aria-hidden=\"true\"\n        />\n      )}\n\n      <Card\n        className={cn(\n          \"transition-all duration-200\",\n          \"hover:shadow-md\",\n          depth === 0 ? \"border-2\" : \"border\",\n          typeColors[conditionType],\n          \"backdrop-blur-sm\",\n        )}\n      >\n        <div className=\"p-4\">\n          {/* Header */}\n          <div className=\"flex items-center justify-between mb-3\">\n            <div className=\"flex items-center gap-2\">\n              <Button\n                variant=\"ghost\"\n                size=\"sm\"\n                className=\"h-6 w-6 p-0\"\n                onClick={() => depth > 0 && toggleGroupExpanded(groupPath)}\n                disabled={depth === 0}\n              >\n                {isExpanded ? (\n                  <ChevronDown className=\"h-4 w-4\" />\n                ) : (\n                  <ChevronRight className=\"h-4 w-4\" />\n                )}\n              </Button>\n\n              <div className=\"flex items-center gap-2\">\n                <Select\n                  value={conditionType}\n                  onValueChange={(value) =>\n                    handleTypeChange(value as ConditionType)\n                  }\n                  disabled={readOnly}\n                >\n                  <SelectTrigger\n                    className={cn(\n                      \"h-8 w-24 font-semibold\",\n                      conditionType === \"or\" &&\n                        \"text-blue-600 dark:text-blue-400\",\n                      conditionType === \"and\" &&\n                        \"text-green-600 dark:text-green-400\",\n                      conditionType === \"none\" &&\n                        \"text-red-600 dark:text-red-400\",\n                    )}\n                  >\n                    <SelectValue />\n                  </SelectTrigger>\n                  <SelectContent>\n                    <SelectItem\n                      value=\"or\"\n                      className=\"text-blue-600 dark:text-blue-400 font-semibold\"\n                    >\n                      {typeLabels.or}\n                    </SelectItem>\n                    <SelectItem\n                      value=\"and\"\n                      className=\"text-green-600 dark:text-green-400 font-semibold\"\n                    >\n                      {typeLabels.and}\n                    </SelectItem>\n                    <SelectItem\n                      value=\"none\"\n                      className=\"text-red-600 dark:text-red-400 font-semibold\"\n                    >\n                      {typeLabels.none}\n                    </SelectItem>\n                  </SelectContent>\n                </Select>\n\n                <Badge variant=\"outline\" className=\"text-xs\">\n                  {items.length} {items.length === 1 ? \"item\" : \"items\"}\n                </Badge>\n\n                {depth > 0 && (\n                  <Badge variant=\"secondary\" className=\"text-xs\">\n                    Level {depth + 1}\n                  </Badge>\n                )}\n              </div>\n            </div>\n\n            <div className=\"flex items-center gap-1\">\n              {!readOnly && (\n                <>\n                  <Button\n                    variant=\"outline\"\n                    size=\"sm\"\n                    onClick={addConstraint}\n                    title=\"Add rule\"\n                    className=\"h-8\"\n                  >\n                    <Plus className=\"h-3.5 w-3.5\" />\n                    <span className=\"ml-1.5 hidden sm:inline\">Rule</span>\n                  </Button>\n                  {depth < maxNestingDepth && (\n                    <Button\n                      variant=\"outline\"\n                      size=\"sm\"\n                      onClick={addNestedGroup}\n                      title=\"Add nested group\"\n                      className=\"h-8\"\n                    >\n                      <GitBranch className=\"h-3.5 w-3.5\" />\n                      <span className=\"ml-1.5 hidden sm:inline\">Group</span>\n                    </Button>\n                  )}\n                  <Button\n                    variant=\"ghost\"\n                    size=\"sm\"\n                    onClick={onDuplicate}\n                    title=\"Duplicate group\"\n                  >\n                    <Copy className=\"h-4 w-4\" />\n                  </Button>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"sm\"\n                    onClick={onRemove}\n                    className=\"text-destructive hover:text-destructive\"\n                    title=\"Remove group\"\n                  >\n                    <Trash2 className=\"h-4 w-4\" />\n                  </Button>\n                </>\n              )}\n            </div>\n          </div>\n\n          {/* Content */}\n          {isExpanded && (\n            <div className=\"space-y-3\">\n              {items.length === 0 ? (\n                <div className=\"rounded-lg border-2 border-dashed border-muted-foreground/25 bg-muted/30 py-8\">\n                  <div className=\"text-center\">\n                    <p className=\"text-sm text-muted-foreground mb-4\">\n                      No conditions yet. Start by adding a rule or group.\n                    </p>\n                    {!readOnly && (\n                      <div className=\"flex justify-center gap-3\">\n                        <Button\n                          variant=\"secondary\"\n                          size=\"default\"\n                          onClick={addConstraint}\n                          className=\"gap-2\"\n                        >\n                          <Plus className=\"h-4 w-4\" />\n                          Add Rule\n                        </Button>\n                        {depth < maxNestingDepth && (\n                          <Button\n                            variant=\"secondary\"\n                            size=\"default\"\n                            onClick={addNestedGroup}\n                            className=\"gap-2\"\n                          >\n                            <Layers className=\"h-4 w-4\" />\n                            Add Group\n                          </Button>\n                        )}\n                      </div>\n                    )}\n                  </div>\n                </div>\n              ) : (\n                items.map((item, index) => (\n                  <div key={`${path.join(\"-\")}-${index}`} className=\"relative\">\n                    {/* Connection dot */}\n                    {depth > 0 && (\n                      <div\n                        className=\"absolute left-[-20px] top-4 w-2 h-2 bg-border rounded-full\"\n                        aria-hidden=\"true\"\n                      />\n                    )}\n\n                    {isConstraint(item) ? (\n                      <TreeConstraintEditor\n                        constraint={item}\n                        path={[...path, index]}\n                        fields={fields}\n                        sampleData={sampleData}\n                        customOperators={customOperators}\n                        onUpdate={(updated) => updateItem(index, updated)}\n                        onRemove={() => removeItem(index)}\n                        onDuplicate={() => duplicateItem(index)}\n                        readOnly={readOnly}\n                      />\n                    ) : (\n                      <TreeConditionGroup\n                        condition={item}\n                        path={[...path, index]}\n                        depth={depth + 1}\n                        fields={fields}\n                        sampleData={sampleData}\n                        customOperators={customOperators}\n                        maxNestingDepth={maxNestingDepth}\n                        onUpdate={(updated) => updateItem(index, updated)}\n                        onRemove={() => removeItem(index)}\n                        onDuplicate={() => duplicateItem(index)}\n                        readOnly={readOnly}\n                        labels={labels}\n                        colors={colors}\n                      />\n                    )}\n                  </div>\n                ))\n              )}\n            </div>\n          )}\n        </div>\n      </Card>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/TreeConstraintEditor.tsx",
    "content": "import type { Constraint } from \"@usex/rule-engine\";\nimport type { FieldConfig } from \"../types\";\nimport { Operators } from \"@usex/rule-engine\";\nimport {\n  Trash2,\n  Regex,\n  Layers,\n  Info,\n  HelpCircle,\n  Copy,\n  Code2,\n  AlertCircle,\n} from \"lucide-react\";\nimport React, { useState, useEffect } from \"react\";\nimport { operatorHelp } from \"../constants/operator-help\";\nimport { cn } from \"../lib/utils\";\nimport { getOperatorConfig } from \"../utils/operators\";\nimport { DynamicFieldSelector } from \"./DynamicFieldSelector\";\nimport { SmartValueInput } from \"./inputs/SmartValueInput\";\nimport { SmartOperatorSelector } from \"./SmartOperatorSelector\";\nimport { RegexValidator } from \"./RegexValidator\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { Card } from \"./ui/card\";\nimport { CollapsibleContent, Collapsible } from \"./ui/collapsible\";\nimport { Input } from \"./ui/input\";\nimport { Label } from \"./ui/label\";\nimport {\n  SheetTrigger,\n  SheetTitle,\n  SheetHeader,\n  SheetDescription,\n  SheetContent,\n  Sheet,\n} from \"./ui/sheet\";\nimport { TabsTrigger, TabsList, Tabs } from \"./ui/tabs\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"./ui/tooltip\";\nimport { VisualFieldSelector } from \"./VisualFieldSelector\";\nimport { AdvancedFieldInput } from \"./AdvancedFieldInput\";\n\ninterface TreeConstraintEditorProps {\n  constraint: Constraint;\n  path?: number[];\n  fields?: FieldConfig[];\n  sampleData?: Record<string, any>;\n  customOperators?: Record<string, any>;\n  onUpdate: (constraint: Constraint) => void;\n  onRemove: () => void;\n  onDuplicate: () => void;\n  readOnly?: boolean;\n}\n\nexport const TreeConstraintEditor: React.FC<TreeConstraintEditorProps> = ({\n  constraint,\n  path: _path,\n  fields,\n  sampleData,\n  customOperators,\n  onUpdate,\n  onRemove,\n  onDuplicate,\n  readOnly = false,\n}) => {\n  const [localConstraint, setLocalConstraint] = useState(constraint);\n  const [isFieldValid, setIsFieldValid] = useState(true);\n  const [isValueValid, setIsValueValid] = useState(true);\n  const [fieldSelectorMode, setFieldSelectorMode] = useState<\n    \"dynamic\" | \"visual\" | \"advanced\"\n  >(\"advanced\");\n  const [showHelp, setShowHelp] = useState(false);\n\n  // Update local state when constraint prop changes\n  useEffect(() => {\n    setLocalConstraint(constraint);\n  }, [constraint]);\n\n  const operatorConfig = getOperatorConfig(localConstraint.operator);\n  const selectedField = fields?.find((f) => f.name === localConstraint.field);\n\n  const handleFieldChange = (field: string) => {\n    const updated = { ...localConstraint, field };\n    setLocalConstraint(updated);\n    onUpdate(updated);\n    setIsFieldValid(!!field);\n  };\n\n  const handleOperatorChange = (operator: any) => {\n    const updated = { ...localConstraint, operator };\n\n    // Reset value if operator changes to one that doesn't need a value\n    const newOperatorConfig = getOperatorConfig(operator);\n    if (newOperatorConfig?.valueType === \"none\") {\n      updated.value = undefined;\n    }\n\n    setLocalConstraint(updated);\n    onUpdate(updated);\n  };\n\n  const handleValueChange = (value: any) => {\n    const updated = { ...localConstraint, value };\n    setLocalConstraint(updated);\n    onUpdate(updated);\n    setIsValueValid(value !== undefined && value !== \"\");\n  };\n\n  const handleMessageChange = (message: string) => {\n    const updated = {\n      ...localConstraint,\n      message: message || undefined,\n    };\n    setLocalConstraint(updated);\n    onUpdate(updated);\n  };\n\n  // Validate constraint\n  const needsValue = operatorConfig?.valueType !== \"none\";\n  const isValid = isFieldValid && (!needsValue || isValueValid);\n\n  return (\n    <Card\n      className={cn(\n        \"overflow-hidden transition-all\",\n        \"hover:shadow-sm\",\n        !isValid && \"border-destructive\",\n      )}\n    >\n      <div className=\"p-4 space-y-4\">\n        {/* Field and Operator Row */}\n        <div className=\"grid grid-cols-1 md:grid-cols-2 gap-3\">\n          <div className=\"space-y-2\">\n            <div className=\"flex items-center justify-between\">\n              <div className=\"flex items-center gap-2\">\n                <Label className=\"text-sm font-medium\">Field</Label>\n                {selectedField?.description && (\n                  <TooltipProvider>\n                    <Tooltip>\n                      <TooltipTrigger>\n                        <Info className=\"h-3 w-3 text-muted-foreground\" />\n                      </TooltipTrigger>\n                      <TooltipContent>\n                        <p className=\"max-w-xs\">{selectedField.description}</p>\n                      </TooltipContent>\n                    </Tooltip>\n                  </TooltipProvider>\n                )}\n              </div>\n              {sampleData && (\n                <Tabs\n                  value={fieldSelectorMode}\n                  onValueChange={(v) =>\n                    setFieldSelectorMode(v as \"dynamic\" | \"visual\" | \"advanced\")\n                  }\n                >\n                  <TabsList className=\"h-7\">\n                    <TabsTrigger value=\"advanced\" className=\"h-6 px-2 text-xs\">\n                      <Regex className=\"h-3 w-3 mr-1\" />\n                      Smart\n                    </TabsTrigger>\n                    <TabsTrigger value=\"dynamic\" className=\"h-6 px-2 text-xs\">\n                      <Code2 className=\"h-3 w-3 mr-1\" />\n                      List\n                    </TabsTrigger>\n                    <TabsTrigger value=\"visual\" className=\"h-6 px-2 text-xs\">\n                      <Layers className=\"h-3 w-3 mr-1\" />\n                      Visual\n                    </TabsTrigger>\n                  </TabsList>\n                </Tabs>\n              )}\n            </div>\n            {fieldSelectorMode === \"advanced\" ? (\n              <AdvancedFieldInput\n                value={localConstraint.field}\n                onChange={handleFieldChange}\n                fields={fields}\n                sampleData={sampleData}\n                disabled={readOnly}\n                allowJsonPath={true}\n                showPreview={true}\n                placeholder=\"Type to search or enter field path...\"\n              />\n            ) : fieldSelectorMode === \"dynamic\" ? (\n              <DynamicFieldSelector\n                value={localConstraint.field}\n                onChange={handleFieldChange}\n                fields={fields}\n                sampleData={sampleData}\n                disabled={readOnly}\n                allowCustom={true}\n                showJsonPath={true}\n              />\n            ) : (\n              <VisualFieldSelector\n                value={localConstraint.field}\n                onChange={handleFieldChange}\n                fields={fields}\n                sampleData={sampleData}\n                disabled={readOnly}\n                allowJsonPath={true}\n                showPreview={true}\n              />\n            )}\n            {!isFieldValid && (\n              <p className=\"text-xs text-destructive\">Field is required</p>\n            )}\n          </div>\n\n          <div className=\"space-y-2\">\n            <Label className=\"text-sm font-medium\">Operator</Label>\n            <div className=\"flex items-center gap-2\">\n              <SmartOperatorSelector\n                value={localConstraint.operator}\n                onChange={handleOperatorChange}\n                fieldName={localConstraint.field}\n                fieldType={selectedField?.type}\n                disabled={readOnly}\n                customOperators={customOperators}\n                className=\"flex-1\"\n              />\n              {localConstraint.operator &&\n                operatorHelp[localConstraint.operator] && (\n                  <TooltipProvider>\n                    <Tooltip>\n                      <TooltipTrigger asChild>\n                        <Button\n                          variant=\"ghost\"\n                          size=\"icon\"\n                          className=\"h-8 w-8\"\n                          onClick={() => setShowHelp(!showHelp)}\n                        >\n                          <HelpCircle className=\"h-4 w-4 text-muted-foreground\" />\n                        </Button>\n                      </TooltipTrigger>\n                      <TooltipContent className=\"max-w-xs\">\n                        <p className=\"font-medium\">\n                          {operatorHelp[localConstraint.operator].name}\n                        </p>\n                        <p className=\"text-xs\">\n                          {operatorHelp[localConstraint.operator].description}\n                        </p>\n                      </TooltipContent>\n                    </Tooltip>\n                  </TooltipProvider>\n                )}\n            </div>\n          </div>\n        </div>\n\n        {/* Operator Help Section */}\n        {showHelp &&\n          localConstraint.operator &&\n          operatorHelp[localConstraint.operator] && (\n            <Collapsible open={showHelp}>\n              <CollapsibleContent>\n                <Card className=\"bg-muted/50 border-muted\">\n                  <div className=\"p-4 space-y-3\">\n                    <div>\n                      <h4 className=\"font-semibold text-sm\">\n                        {operatorHelp[localConstraint.operator].name}\n                      </h4>\n                      <p className=\"text-sm text-muted-foreground mt-1\">\n                        {operatorHelp[localConstraint.operator].description}\n                      </p>\n                    </div>\n\n                    {operatorHelp[localConstraint.operator].examples.length >\n                      0 && (\n                      <div>\n                        <h5 className=\"text-xs font-medium text-muted-foreground mb-2\">\n                          Examples:\n                        </h5>\n                        <div className=\"space-y-2\">\n                          {operatorHelp[localConstraint.operator].examples.map(\n                            (example, index) => (\n                              <div\n                                key={index}\n                                className=\"bg-background rounded-md p-2 text-xs\"\n                              >\n                                <code className=\"text-primary\">\n                                  {example.field} {localConstraint.operator}{\" \"}\n                                  {JSON.stringify(example.value)}\n                                </code>\n                                <p className=\"text-muted-foreground mt-1\">\n                                  {example.explanation}\n                                </p>\n                              </div>\n                            ),\n                          )}\n                        </div>\n                      </div>\n                    )}\n\n                    {operatorHelp[localConstraint.operator].tips &&\n                      operatorHelp[localConstraint.operator].tips!.length >\n                        0 && (\n                        <div>\n                          <h5 className=\"text-xs font-medium text-muted-foreground mb-2\">\n                            Tips:\n                          </h5>\n                          <ul className=\"space-y-1\">\n                            {operatorHelp[localConstraint.operator].tips!.map(\n                              (tip, index) => (\n                                <li\n                                  key={index}\n                                  className=\"text-xs text-muted-foreground flex items-start\"\n                                >\n                                  <span className=\"mr-2\">•</span>\n                                  <span>{tip}</span>\n                                </li>\n                              ),\n                            )}\n                          </ul>\n                        </div>\n                      )}\n                  </div>\n                </Card>\n              </CollapsibleContent>\n            </Collapsible>\n          )}\n\n        {/* Value Input */}\n        {operatorConfig?.valueType !== \"none\" && (\n          <div className=\"space-y-2\">\n            <div className=\"flex items-center gap-2\">\n              <Label className=\"text-sm font-medium\">Value</Label>\n              {operatorConfig?.valueType && (\n                <Badge variant=\"outline\" className=\"text-xs\">\n                  {operatorConfig.valueType}\n                </Badge>\n              )}\n              {/* Regex Helper for matches/not matches operators */}\n              {(localConstraint.operator === Operators.Matches ||\n                localConstraint.operator === Operators.NotMatches) && (\n                <Sheet>\n                  <SheetTrigger asChild>\n                    <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2\">\n                      <Regex className=\"h-3 w-3 mr-1\" />\n                      Regex Helper\n                    </Button>\n                  </SheetTrigger>\n                  <SheetContent className=\"w-[500px] sm:max-w-[500px]\">\n                    <SheetHeader>\n                      <SheetTitle>Regular Expression Helper</SheetTitle>\n                      <SheetDescription>\n                        Test and validate your regular expression pattern\n                      </SheetDescription>\n                    </SheetHeader>\n                    <div className=\"mt-6\">\n                      <RegexValidator\n                        value={\n                          typeof localConstraint.value === \"string\"\n                            ? localConstraint.value\n                            : \"\"\n                        }\n                        onChange={handleValueChange}\n                        testString={\n                          selectedField && sampleData\n                            ? String(sampleData[selectedField.name] || \"\")\n                            : \"\"\n                        }\n                      />\n                    </div>\n                  </SheetContent>\n                </Sheet>\n              )}\n            </div>\n            <SmartValueInput\n              value={localConstraint.value}\n              onChange={handleValueChange}\n              operator={localConstraint.operator}\n              field={selectedField}\n              sampleData={sampleData}\n              disabled={readOnly}\n            />\n            {!isValueValid && needsValue && (\n              <p className=\"text-xs text-destructive\">Value is required</p>\n            )}\n          </div>\n        )}\n\n        {/* Error Message */}\n        <div className=\"space-y-2\">\n          <div className=\"flex items-center gap-2\">\n            <Label className=\"text-sm font-medium\">Error Message</Label>\n            <Badge variant=\"outline\" className=\"text-xs\">\n              Optional\n            </Badge>\n          </div>\n          <div className=\"relative\">\n            <AlertCircle className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n            <Input\n              value={localConstraint.message || \"\"}\n              onChange={(e) => handleMessageChange(e.target.value)}\n              placeholder=\"Custom error message when this rule fails\"\n              disabled={readOnly}\n              className=\"pl-10\"\n            />\n          </div>\n        </div>\n\n        {/* Actions and Preview */}\n        <div className=\"flex items-center justify-between pt-2\">\n          <div className=\"flex items-center gap-2\">\n            <div className=\"text-xs text-muted-foreground font-mono\">\n              {localConstraint.field}{\" \"}\n              {operatorConfig?.label || localConstraint.operator}\n              {localConstraint.value !== undefined && (\n                <> {JSON.stringify(localConstraint.value)}</>\n              )}\n            </div>\n            {localConstraint.operator &&\n              operatorHelp[localConstraint.operator] && (\n                <TooltipProvider>\n                  <Tooltip>\n                    <TooltipTrigger asChild>\n                      <Info className=\"h-3 w-3 text-muted-foreground cursor-help\" />\n                    </TooltipTrigger>\n                    <TooltipContent className=\"max-w-sm\">\n                      <div className=\"space-y-2\">\n                        <p className=\"font-medium\">\n                          {operatorHelp[localConstraint.operator].name}\n                        </p>\n                        <p className=\"text-xs\">\n                          {operatorHelp[localConstraint.operator].description}\n                        </p>\n                        {operatorHelp[localConstraint.operator].tips &&\n                          operatorHelp[localConstraint.operator].tips!.length >\n                            0 && (\n                            <div className=\"text-xs space-y-1 pt-1 border-t\">\n                              {operatorHelp[localConstraint.operator]\n                                .tips!.slice(0, 1)\n                                .map((tip, i) => (\n                                  <p key={i} className=\"text-muted-foreground\">\n                                    💡 {tip}\n                                  </p>\n                                ))}\n                            </div>\n                          )}\n                      </div>\n                    </TooltipContent>\n                  </Tooltip>\n                </TooltipProvider>\n              )}\n          </div>\n\n          {!readOnly && (\n            <div className=\"flex gap-1\">\n              <Button\n                variant=\"ghost\"\n                size=\"sm\"\n                onClick={onDuplicate}\n                title=\"Duplicate\"\n              >\n                <Copy className=\"h-4 w-4\" />\n              </Button>\n              <Button\n                variant=\"ghost\"\n                size=\"sm\"\n                onClick={onRemove}\n                className=\"text-destructive hover:text-destructive\"\n                title=\"Remove\"\n              >\n                <Trash2 className=\"h-4 w-4\" />\n              </Button>\n            </div>\n          )}\n        </div>\n      </div>\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/TreeRuleBuilder.tsx",
    "content": "import type { Condition } from \"@usex/rule-engine\";\nimport type { FieldConfig } from \"../types\";\nimport { RuleEngine } from \"@usex/rule-engine\";\nimport {\n  TestTube2,\n  Save,\n  Plus,\n  PlayCircle,\n  Minimize2,\n  Maximize2,\n  Keyboard,\n  GitBranch,\n  FileJson,\n  AlertCircle,\n} from \"lucide-react\";\nimport React, { useState } from \"react\";\nimport { Toaster, toast } from \"sonner\";\nimport { useKeyboardShortcuts } from \"../hooks/use-keyboard-shortcuts\";\nimport { cn } from \"../lib/utils\";\nimport { useEnhancedRuleStore } from \"../stores/enhanced-rule-store\";\nimport { AnimatedNumber } from \"./AnimatedNumber\";\nimport { EditableJsonViewer } from \"./EditableJsonViewer\";\nimport { JsonViewer } from \"./JsonVisualizer\";\nimport { HistoryViewer } from \"./HistoryViewer\";\nimport { ThemeToggle } from \"./ThemeToggle\";\nimport { TreeConditionGroup } from \"./TreeConditionGroup\";\nimport { AlertDescription, Alert } from \"./ui/alert\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Separator } from \"./ui/separator\";\nimport {\n  SheetTrigger,\n  SheetTitle,\n  SheetHeader,\n  SheetDescription,\n  SheetContent,\n  Sheet,\n} from \"./ui/sheet\";\nimport { Textarea } from \"./ui/textarea\";\nimport { UndoRedoInfo } from \"./UndoRedoInfo\";\n\ninterface TreeRuleBuilderProps {\n  fields?: FieldConfig[];\n  sampleData?: Record<string, any>;\n  onChange?: (rule: any) => void;\n  onSave?: (rule: any) => void | Promise<void>;\n  onExport?: (rule: any, format: \"json\" | \"yaml\") => void;\n  onImport?: (data: string, format: \"json\" | \"yaml\") => void;\n  readOnly?: boolean;\n  className?: string;\n  showJsonViewer?: boolean;\n  showToolbar?: boolean;\n  maxNestingDepth?: number;\n  customOperators?: Record<string, any>;\n  theme?: \"light\" | \"dark\" | \"system\";\n  labels?: {\n    addGroup?: string;\n    addRule?: string;\n    removeGroup?: string;\n    duplicateGroup?: string;\n    or?: string;\n    and?: string;\n    none?: string;\n    noRules?: string;\n    importSuccess?: string;\n    exportSuccess?: string;\n    saveSuccess?: string;\n  };\n  colors?: {\n    or?: string;\n    and?: string;\n    none?: string;\n  };\n  keyboardShortcuts?: {\n    undo?: {\n      key: string;\n      ctrl?: boolean;\n      cmd?: boolean;\n      shift?: boolean;\n      alt?: boolean;\n    };\n    redo?: {\n      key: string;\n      ctrl?: boolean;\n      cmd?: boolean;\n      shift?: boolean;\n      alt?: boolean;\n    };\n    save?: {\n      key: string;\n      ctrl?: boolean;\n      cmd?: boolean;\n      shift?: boolean;\n      alt?: boolean;\n    };\n    test?: {\n      key: string;\n      ctrl?: boolean;\n      cmd?: boolean;\n      shift?: boolean;\n      alt?: boolean;\n    };\n    addGroup?: {\n      key: string;\n      ctrl?: boolean;\n      cmd?: boolean;\n      shift?: boolean;\n      alt?: boolean;\n    };\n    expandAll?: {\n      key: string;\n      ctrl?: boolean;\n      cmd?: boolean;\n      shift?: boolean;\n      alt?: boolean;\n    };\n    collapseAll?: {\n      key: string;\n      ctrl?: boolean;\n      cmd?: boolean;\n      shift?: boolean;\n      alt?: boolean;\n    };\n    help?: {\n      key: string;\n      ctrl?: boolean;\n      cmd?: boolean;\n      shift?: boolean;\n      alt?: boolean;\n    };\n  };\n}\n\nexport const TreeRuleBuilder: React.FC<TreeRuleBuilderProps> = ({\n  fields = [],\n  sampleData = {},\n  onChange,\n  onSave,\n  onExport,\n  onImport,\n  readOnly = false,\n  className,\n  showJsonViewer = true,\n  showToolbar = true,\n  maxNestingDepth = 10,\n  customOperators,\n  theme: _propTheme = \"system\",\n  labels = {},\n  colors = {},\n  keyboardShortcuts = {},\n}) => {\n  const {\n    rule,\n    updateConditions,\n    undo,\n    redo,\n    canUndo,\n    canRedo,\n    getUndoInfo,\n    getRedoInfo,\n    getHistoryInfo,\n    expandAll,\n    collapseAll,\n  } = useEnhancedRuleStore();\n\n  const [expandedJson, setExpandedJson] = useState(false);\n  const [isSaving, setIsSaving] = useState(false);\n  const [testData, setTestData] = useState(JSON.stringify(sampleData, null, 2));\n  const [testResult, setTestResult] = useState<any>(null);\n  const [isTestRunning, setIsTestRunning] = useState(false);\n  const [isTestSheetOpen, setIsTestSheetOpen] = useState(false);\n  const [showKeyboardShortcuts, setShowKeyboardShortcuts] = useState(false);\n\n  // Default shortcuts\n  const defaultShortcuts = {\n    undo: { key: \"z\", ctrl: true },\n    redo: { key: \"y\", ctrl: true },\n    save: { key: \"s\", ctrl: true },\n    test: { key: \"t\", ctrl: true },\n    addGroup: { key: \"r\", ctrl: true },\n    expandAll: { key: \"e\", ctrl: true, shift: true },\n    collapseAll: { key: \"c\", ctrl: true, shift: true },\n    help: { key: \"?\", shift: true },\n  };\n\n  // Merge custom shortcuts with defaults\n  const mergedShortcuts = {\n    undo: keyboardShortcuts.undo || defaultShortcuts.undo,\n    redo: keyboardShortcuts.redo || defaultShortcuts.redo,\n    save: keyboardShortcuts.save || defaultShortcuts.save,\n    test: keyboardShortcuts.test || defaultShortcuts.test,\n    addGroup: keyboardShortcuts.addGroup || defaultShortcuts.addGroup,\n    expandAll: keyboardShortcuts.expandAll || defaultShortcuts.expandAll,\n    collapseAll: keyboardShortcuts.collapseAll || defaultShortcuts.collapseAll,\n    help: keyboardShortcuts.help || defaultShortcuts.help,\n  };\n\n  // Merge default labels\n  const mergedLabels = {\n    addGroup: \"Add Condition Group\",\n    addRule: \"Add Rule\",\n    removeGroup: \"Remove Group\",\n    duplicateGroup: \"Duplicate Group\",\n    or: \"OR\",\n    and: \"AND\",\n    none: \"NONE\",\n    noRules: \"No rules defined yet. Start by adding a condition group.\",\n    importSuccess: \"Rule imported successfully\",\n    exportSuccess: \"Rule exported successfully\",\n    saveSuccess: \"Rule saved successfully\",\n    ...labels,\n  };\n\n  // Debounce onChange\n  const onChangeTimerRef = React.useRef<NodeJS.Timeout | null>(null);\n\n  React.useEffect(() => {\n    if (onChange) {\n      if (onChangeTimerRef.current) {\n        clearTimeout(onChangeTimerRef.current);\n      }\n\n      onChangeTimerRef.current = setTimeout(() => {\n        onChange(rule);\n      }, 100);\n    }\n\n    return () => {\n      if (onChangeTimerRef.current) {\n        clearTimeout(onChangeTimerRef.current);\n      }\n    };\n  }, [rule]);\n\n  const conditions = React.useMemo(() => {\n    if (!rule.conditions) return [];\n    return Array.isArray(rule.conditions) ? rule.conditions : [rule.conditions];\n  }, [rule.conditions]);\n\n  const addRootConditionGroup = (type: \"or\" | \"and\" | \"none\" = \"or\") => {\n    const newCondition: Condition = { [type]: [] };\n    updateConditions([...conditions, newCondition]);\n    toast.success(\"Added new condition group\");\n  };\n\n  const handleTestRule = async () => {\n    setIsTestRunning(true);\n    setTestResult(null);\n\n    try {\n      const data = JSON.parse(testData);\n      const result = await RuleEngine.evaluate(rule, data);\n\n      const isPassed = Array.isArray(result)\n        ? result.some((r) => r.isPassed)\n        : result.isPassed;\n\n      setTestResult({\n        success: true,\n        result,\n        passed: isPassed,\n      });\n\n      toast.success(isPassed ? \"Rule passed!\" : \"Rule failed!\");\n    } catch (error: any) {\n      setTestResult({\n        success: false,\n        error: error.message,\n      });\n      toast.error(\"Error evaluating rule\");\n    } finally {\n      setIsTestRunning(false);\n    }\n  };\n\n  const updateCondition = (index: number, condition: Condition) => {\n    const updatedConditions = [...conditions];\n    updatedConditions[index] = condition;\n    updateConditions(updatedConditions);\n  };\n\n  const removeCondition = (index: number) => {\n    updateConditions(conditions.filter((_, i) => i !== index));\n    toast.success(\"Removed condition group\");\n  };\n\n  const duplicateCondition = (index: number) => {\n    const conditionToDuplicate = conditions[index];\n    const duplicated = JSON.parse(JSON.stringify(conditionToDuplicate));\n    updateConditions([...conditions, duplicated]);\n    toast.success(\"Duplicated condition group\");\n  };\n\n  async function handleSave() {\n    if (!onSave) return;\n\n    setIsSaving(true);\n    try {\n      await onSave(rule);\n      toast.success(mergedLabels.saveSuccess);\n    } catch {\n      toast.error(\"Failed to save rule\");\n    } finally {\n      setIsSaving(false);\n    }\n  }\n\n  // Keyboard shortcuts\n  useKeyboardShortcuts([\n    {\n      ...mergedShortcuts.undo,\n      handler: () => canUndo() && undo(),\n      description: \"Undo last action\",\n    },\n    {\n      ...mergedShortcuts.redo,\n      handler: () => canRedo() && redo(),\n      description: \"Redo last action\",\n    },\n    {\n      key: \"z\",\n      ctrl: true,\n      shift: true,\n      handler: () => canRedo() && redo(),\n      description: \"Redo last action\",\n    },\n    {\n      ...mergedShortcuts.save,\n      handler: () => onSave && !readOnly && handleSave(),\n      description: \"Save rule\",\n    },\n    {\n      ...mergedShortcuts.expandAll,\n      handler: () => expandAll(),\n      description: \"Expand all groups\",\n    },\n    {\n      ...mergedShortcuts.collapseAll,\n      handler: () => collapseAll(),\n      description: \"Collapse all groups\",\n    },\n    {\n      ...mergedShortcuts.addGroup,\n      handler: () => !readOnly && addRootConditionGroup(),\n      description: \"Add new rule group\",\n    },\n    {\n      ...mergedShortcuts.test,\n      handler: () => setIsTestSheetOpen(true),\n      description: \"Test rule\",\n    },\n    {\n      ...mergedShortcuts.help,\n      handler: () => setShowKeyboardShortcuts(true),\n      description: \"Show keyboard shortcuts\",\n    },\n  ]);\n\n  return (\n    <div className={cn(\"space-y-4\", className)}>\n      <Toaster position=\"top-center\" />\n\n      {/* Header */}\n      <Card>\n        <CardHeader className=\"pb-3\">\n          <div className=\"flex items-center justify-between\">\n            <div className=\"flex items-center gap-3\">\n              <CardTitle>Rule Builder</CardTitle>\n              <Badge variant=\"outline\">\n                <AnimatedNumber value={conditions.length} />\n                <span className=\"ml-1\">groups</span>\n              </Badge>\n            </div>\n            <div className=\"flex items-center gap-2\">\n              {showToolbar && (\n                <>\n                  <Sheet\n                    open={isTestSheetOpen}\n                    onOpenChange={setIsTestSheetOpen}\n                  >\n                    <SheetTrigger asChild>\n                      <Button variant=\"outline\" size=\"sm\">\n                        <TestTube2 className=\"h-4 w-4 mr-2\" />\n                        Test Rule\n                      </Button>\n                    </SheetTrigger>\n                    <SheetContent className=\"w-[500px] sm:max-w-[500px]\">\n                      <SheetHeader>\n                        <SheetTitle>Test Rule</SheetTitle>\n                        <SheetDescription>\n                          Test your rule with sample data to see how it behaves\n                        </SheetDescription>\n                      </SheetHeader>\n                      <div className=\"mt-6 space-y-4\">\n                        <div>\n                          <label className=\"text-sm font-medium mb-2 block\">\n                            Test Data (JSON)\n                          </label>\n                          <Textarea\n                            value={testData}\n                            onChange={(e) => setTestData(e.target.value)}\n                            className=\"font-mono text-sm min-h-[300px]\"\n                            placeholder=\"Enter test data in JSON format\"\n                          />\n                        </div>\n\n                        <Button\n                          onClick={handleTestRule}\n                          disabled={isTestRunning}\n                          className=\"w-full\"\n                        >\n                          <PlayCircle className=\"h-4 w-4 mr-2\" />\n                          {isTestRunning ? \"Running...\" : \"Run Test\"}\n                        </Button>\n\n                        {testResult && (\n                          <div className=\"space-y-4\">\n                            <Alert\n                              variant={\n                                testResult.success\n                                  ? testResult.passed\n                                    ? \"default\"\n                                    : \"destructive\"\n                                  : \"destructive\"\n                              }\n                            >\n                              <AlertCircle className=\"h-4 w-4\" />\n                              <AlertDescription>\n                                {testResult.success\n                                  ? testResult.passed\n                                    ? \"Rule evaluation passed\"\n                                    : \"Rule evaluation failed\"\n                                  : \"Error during evaluation\"}\n                              </AlertDescription>\n                            </Alert>\n\n                            {testResult.success && (\n                              <div className=\"space-y-2\">\n                                <label className=\"text-sm font-medium block\">\n                                  Result\n                                </label>\n                                <Card className=\"overflow-hidden\">\n                                  <CardContent className=\"p-4\">\n                                    <JsonViewer\n                                      data={testResult.result}\n                                      rootName=\"result\"\n                                      defaultExpanded={true}\n                                      className=\"max-w-full\"\n                                      highlightLogicalOperators={true}\n                                    />\n                                  </CardContent>\n                                </Card>\n                              </div>\n                            )}\n\n                            {testResult.error && (\n                              <div>\n                                <label className=\"text-sm font-medium mb-2 block\">\n                                  Error\n                                </label>\n                                <pre className=\"text-xs bg-destructive/10 text-destructive p-3 rounded-md\">\n                                  {testResult.error}\n                                </pre>\n                              </div>\n                            )}\n                          </div>\n                        )}\n                      </div>\n                    </SheetContent>\n                  </Sheet>\n\n                  <Separator orientation=\"vertical\" className=\"h-6\" />\n\n                  {/* History controls */}\n                  <UndoRedoInfo\n                    canUndo={canUndo()}\n                    canRedo={canRedo()}\n                    onUndo={undo}\n                    onRedo={redo}\n                    undoInfo={getUndoInfo()}\n                    redoInfo={getRedoInfo()}\n                    historyInfo={getHistoryInfo()}\n                  />\n\n                  <Separator orientation=\"vertical\" className=\"h-6\" />\n\n                  {/* History Viewer */}\n                  <HistoryViewer />\n\n                  {onSave && (\n                    <>\n                      <Separator orientation=\"vertical\" className=\"h-6\" />\n                      <Button\n                        variant=\"ghost\"\n                        size=\"icon\"\n                        onClick={handleSave}\n                        disabled={readOnly || isSaving}\n                        title=\"Save\"\n                      >\n                        <Save\n                          className={cn(\"h-4 w-4\", isSaving && \"animate-pulse\")}\n                        />\n                      </Button>\n                    </>\n                  )}\n\n                  {onExport && (\n                    <>\n                      <Separator orientation=\"vertical\" className=\"h-6\" />\n                      <Button\n                        variant=\"ghost\"\n                        size=\"icon\"\n                        onClick={() => {\n                          onExport(rule, \"json\");\n                          toast.success(mergedLabels.exportSuccess);\n                        }}\n                        title=\"Export JSON\"\n                      >\n                        <FileJson className=\"h-4 w-4\" />\n                      </Button>\n                    </>\n                  )}\n\n                  <Separator orientation=\"vertical\" className=\"h-6\" />\n\n                  {/* Expand/Collapse buttons */}\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    onClick={expandAll}\n                    title=\"Expand all groups (Ctrl+Shift+E)\"\n                  >\n                    <Maximize2 className=\"h-4 w-4\" />\n                  </Button>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    onClick={collapseAll}\n                    title=\"Collapse all groups (Ctrl+Shift+C)\"\n                  >\n                    <Minimize2 className=\"h-4 w-4\" />\n                  </Button>\n\n                  <Separator orientation=\"vertical\" className=\"h-6\" />\n\n                  {/* Keyboard shortcuts */}\n                  <Sheet\n                    open={showKeyboardShortcuts}\n                    onOpenChange={setShowKeyboardShortcuts}\n                  >\n                    <SheetTrigger asChild>\n                      <Button\n                        variant=\"ghost\"\n                        size=\"icon\"\n                        title=\"Keyboard shortcuts (?)\"\n                      >\n                        <Keyboard className=\"h-4 w-4\" />\n                      </Button>\n                    </SheetTrigger>\n                    <SheetContent>\n                      <SheetHeader>\n                        <SheetTitle>Keyboard Shortcuts</SheetTitle>\n                        <SheetDescription>\n                          Use these shortcuts to work faster with the rule\n                          builder\n                        </SheetDescription>\n                      </SheetHeader>\n                      <div className=\"mt-6 space-y-4\">\n                        <div className=\"space-y-2\">\n                          <h4 className=\"font-medium\">General</h4>\n                          <div className=\"space-y-1 text-sm\">\n                            <div className=\"flex justify-between\">\n                              <span>Undo</span>\n                              <kbd className=\"px-2 py-1 bg-muted rounded text-xs\">\n                                Ctrl+Z\n                              </kbd>\n                            </div>\n                            <div className=\"flex justify-between\">\n                              <span>Redo</span>\n                              <kbd className=\"px-2 py-1 bg-muted rounded text-xs\">\n                                Ctrl+Y\n                              </kbd>\n                            </div>\n                            <div className=\"flex justify-between\">\n                              <span>Save</span>\n                              <kbd className=\"px-2 py-1 bg-muted rounded text-xs\">\n                                Ctrl+S\n                              </kbd>\n                            </div>\n                          </div>\n                        </div>\n\n                        <div className=\"space-y-2\">\n                          <h4 className=\"font-medium\">Navigation</h4>\n                          <div className=\"space-y-1 text-sm\">\n                            <div className=\"flex justify-between\">\n                              <span>Expand all</span>\n                              <kbd className=\"px-2 py-1 bg-muted rounded text-xs\">\n                                Ctrl+Shift+E\n                              </kbd>\n                            </div>\n                            <div className=\"flex justify-between\">\n                              <span>Collapse all</span>\n                              <kbd className=\"px-2 py-1 bg-muted rounded text-xs\">\n                                Ctrl+Shift+C\n                              </kbd>\n                            </div>\n                          </div>\n                        </div>\n\n                        <div className=\"space-y-2\">\n                          <h4 className=\"font-medium\">Actions</h4>\n                          <div className=\"space-y-1 text-sm\">\n                            <div className=\"flex justify-between\">\n                              <span>Add rule group</span>\n                              <kbd className=\"px-2 py-1 bg-muted rounded text-xs\">\n                                Ctrl+R\n                              </kbd>\n                            </div>\n                            <div className=\"flex justify-between\">\n                              <span>Test rule</span>\n                              <kbd className=\"px-2 py-1 bg-muted rounded text-xs\">\n                                Ctrl+T\n                              </kbd>\n                            </div>\n                            <div className=\"flex justify-between\">\n                              <span>Show shortcuts</span>\n                              <kbd className=\"px-2 py-1 bg-muted rounded text-xs\">\n                                ?\n                              </kbd>\n                            </div>\n                          </div>\n                        </div>\n                      </div>\n                    </SheetContent>\n                  </Sheet>\n                </>\n              )}\n              <ThemeToggle />\n            </div>\n          </div>\n        </CardHeader>\n      </Card>\n\n      <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-4\">\n        {/* Builder Area */}\n        <div className=\"lg:col-span-2 space-y-4\">\n          {conditions.length === 0 ? (\n            <Card className=\"border-2 border-dashed border-muted-foreground/25 bg-muted/10\">\n              <CardContent className=\"py-16\">\n                <div className=\"text-center\">\n                  <div className=\"mx-auto w-12 h-12 rounded-full bg-muted flex items-center justify-center mb-4\">\n                    <GitBranch className=\"h-6 w-6 text-muted-foreground\" />\n                  </div>\n                  <h3 className=\"text-lg font-medium mb-2\">No rules defined</h3>\n                  <p className=\"text-sm text-muted-foreground mb-6 max-w-sm mx-auto\">\n                    {mergedLabels.noRules}\n                  </p>\n                  {!readOnly && (\n                    <div className=\"flex justify-center gap-3\">\n                      <Button\n                        onClick={() => addRootConditionGroup(\"or\")}\n                        size=\"default\"\n                        className=\"gap-2\"\n                      >\n                        <Plus className=\"h-4 w-4\" />\n                        Add {mergedLabels.or} Group\n                      </Button>\n                      <Button\n                        onClick={() => addRootConditionGroup(\"and\")}\n                        variant=\"secondary\"\n                        size=\"default\"\n                        className=\"gap-2\"\n                      >\n                        <Plus className=\"h-4 w-4\" />\n                        Add {mergedLabels.and} Group\n                      </Button>\n                    </div>\n                  )}\n                </div>\n              </CardContent>\n            </Card>\n          ) : (\n            <>\n              <div className=\"space-y-4\">\n                {conditions.map((condition, index) => (\n                  <TreeConditionGroup\n                    key={`condition-${index}`}\n                    condition={condition}\n                    path={[index]}\n                    depth={0}\n                    fields={fields}\n                    sampleData={sampleData}\n                    customOperators={customOperators}\n                    maxNestingDepth={maxNestingDepth}\n                    onUpdate={(updated) => updateCondition(index, updated)}\n                    onRemove={() => removeCondition(index)}\n                    onDuplicate={() => duplicateCondition(index)}\n                    readOnly={readOnly}\n                    labels={mergedLabels}\n                    colors={colors}\n                  />\n                ))}\n              </div>\n              {!readOnly && (\n                <Button\n                  onClick={() => addRootConditionGroup()}\n                  variant=\"outline\"\n                  className=\"w-full\"\n                >\n                  <Plus className=\"h-4 w-4 mr-2\" />\n                  {mergedLabels.addGroup}\n                </Button>\n              )}\n            </>\n          )}\n        </div>\n\n        {/* JSON Viewer */}\n        {showJsonViewer && (\n          <div className=\"lg:col-span-1\">\n            <div className=\"sticky top-4\">\n              <EditableJsonViewer\n                rule={rule}\n                onUpdate={(updatedRule) => {\n                  updateConditions(updatedRule.conditions);\n                }}\n                onImport={(imported) => {\n                  if (onImport) {\n                    onImport(JSON.stringify(imported), \"json\");\n                  }\n                  updateConditions(imported.conditions);\n                  toast.success(mergedLabels.importSuccess);\n                }}\n                expanded={expandedJson}\n                onExpandedChange={setExpandedJson}\n                readOnly={readOnly}\n                sampleData={sampleData}\n                showEvaluator={true}\n              />\n            </div>\n          </div>\n        )}\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/UndoRedoInfo.tsx",
    "content": "import React from \"react\";\nimport { RotateCw, RotateCcw, Clock } from \"lucide-react\";\nimport { Button } from \"./ui/button\";\nimport { PopoverTrigger, PopoverContent, Popover } from \"./ui/popover\";\nimport { ScrollArea } from \"./ui/scroll-area\";\nimport { Separator } from \"./ui/separator\";\nimport { Badge } from \"./ui/badge\";\nimport { cn } from \"../lib/utils\";\nimport type { HistoryEntry } from \"../stores/enhanced-rule-store\";\nimport { formatDistanceToNow } from \"date-fns\";\n\ninterface UndoRedoInfoProps {\n  canUndo: boolean;\n  canRedo: boolean;\n  onUndo: () => void;\n  onRedo: () => void;\n  undoInfo: HistoryEntry | null;\n  redoInfo: HistoryEntry | null;\n  historyInfo: { current: number; total: number; entries: HistoryEntry[] };\n  className?: string;\n}\n\nexport const UndoRedoInfo: React.FC<UndoRedoInfoProps> = ({\n  canUndo,\n  canRedo,\n  onUndo,\n  onRedo,\n  undoInfo,\n  redoInfo,\n  historyInfo,\n  className,\n}) => {\n  return (\n    <div className={cn(\"flex items-center gap-1\", className)}>\n      <Popover>\n        <PopoverTrigger asChild>\n          <Button\n            variant=\"ghost\"\n            size=\"icon\"\n            onClick={onUndo}\n            disabled={!canUndo}\n            title={\n              undoInfo\n                ? `Undo: ${undoInfo.description} (Ctrl+Z)`\n                : \"Undo (Ctrl+Z)\"\n            }\n          >\n            <RotateCcw className=\"h-4 w-4\" />\n          </Button>\n        </PopoverTrigger>\n        <PopoverContent className=\"w-80\" align=\"end\">\n          <div className=\"space-y-3\">\n            <div className=\"flex items-center justify-between\">\n              <h4 className=\"font-medium\">History</h4>\n              <Badge variant=\"outline\">\n                {historyInfo.current + 1} / {historyInfo.total}\n              </Badge>\n            </div>\n            <Separator />\n            <ScrollArea className=\"h-[300px]\">\n              <div className=\"space-y-2\">\n                {historyInfo.entries.map((entry, index) => (\n                  <div\n                    key={index}\n                    className={cn(\n                      \"p-2 rounded-md border text-sm\",\n                      index === historyInfo.current &&\n                        \"bg-primary/10 border-primary\",\n                      index < historyInfo.current && \"opacity-60\",\n                    )}\n                  >\n                    <div className=\"flex items-center justify-between mb-1\">\n                      <span className=\"font-medium\">{entry.action}</span>\n                      <span className=\"text-xs text-muted-foreground\">\n                        {formatDistanceToNow(entry.timestamp, {\n                          addSuffix: true,\n                        })}\n                      </span>\n                    </div>\n                    <p className=\"text-xs text-muted-foreground\">\n                      {entry.description}\n                    </p>\n                  </div>\n                ))}\n              </div>\n            </ScrollArea>\n            <div className=\"text-xs text-muted-foreground space-y-1\">\n              <p>• Press Ctrl+Z to undo</p>\n              <p>• Press Ctrl+Y or Ctrl+Shift+Z to redo</p>\n            </div>\n          </div>\n        </PopoverContent>\n      </Popover>\n\n      <Button\n        variant=\"ghost\"\n        size=\"icon\"\n        onClick={onRedo}\n        disabled={!canRedo}\n        title={\n          redoInfo ? `Redo: ${redoInfo.description} (Ctrl+Y)` : \"Redo (Ctrl+Y)\"\n        }\n      >\n        <RotateCw className=\"h-4 w-4\" />\n      </Button>\n\n      <Separator orientation=\"vertical\" className=\"h-6 mx-1\" />\n\n      <div className=\"flex items-center gap-1 px-2\">\n        <Clock className=\"h-3 w-3 text-muted-foreground\" />\n        <span className=\"text-xs text-muted-foreground\">\n          {historyInfo.entries[historyInfo.current]?.timestamp &&\n            formatDistanceToNow(\n              historyInfo.entries[historyInfo.current].timestamp,\n              { addSuffix: true },\n            )}\n        </span>\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/ValueInput.tsx",
    "content": "import React from \"react\";\nimport { Input } from \"./ui/input\";\nimport { Button } from \"./ui/button\";\nimport { X, Plus } from \"lucide-react\";\nimport type { ValueInputProps } from \"../types\";\nimport { getOperatorConfig } from \"../utils/operators\";\nimport { cn } from \"../lib/utils\";\n\nexport const ValueInput: React.FC<ValueInputProps> = ({\n  value,\n  onChange,\n  operator,\n  disabled = false,\n  className,\n  placeholder = \"Enter value\",\n}) => {\n  const operatorConfig = getOperatorConfig(operator);\n  const valueType = operatorConfig?.valueType || \"single\";\n\n  if (valueType === \"none\") {\n    return null;\n  }\n\n  if (valueType === \"multiple\") {\n    const arrayValue = Array.isArray(value) ? value : value ? [value] : [];\n\n    return (\n      <div className={cn(\"space-y-2\", className)}>\n        {arrayValue.map((item, index) => (\n          <div key={index} className=\"flex gap-2\">\n            <Input\n              value={item}\n              onChange={(e) => {\n                const newValue = [...arrayValue];\n                newValue[index] = e.target.value;\n                onChange(newValue);\n              }}\n              placeholder={placeholder}\n              disabled={disabled}\n            />\n            <Button\n              type=\"button\"\n              variant=\"ghost\"\n              size=\"icon\"\n              onClick={() => {\n                const newValue = arrayValue.filter((_, i) => i !== index);\n                onChange(newValue.length > 0 ? newValue : undefined);\n              }}\n              disabled={disabled}\n            >\n              <X className=\"h-4 w-4\" />\n            </Button>\n          </div>\n        ))}\n        <Button\n          type=\"button\"\n          variant=\"outline\"\n          size=\"sm\"\n          onClick={() => {\n            onChange([...arrayValue, \"\"]);\n          }}\n          disabled={disabled}\n          className=\"w-full\"\n        >\n          <Plus className=\"h-4 w-4 mr-2\" />\n          Add Value\n        </Button>\n      </div>\n    );\n  }\n\n  if (valueType === \"range\") {\n    const rangeValue = Array.isArray(value) ? value : [value || \"\", \"\"];\n\n    return (\n      <div className={cn(\"flex gap-2 items-center\", className)}>\n        <Input\n          value={rangeValue[0] || \"\"}\n          onChange={(e) => {\n            onChange([e.target.value, rangeValue[1] || \"\"]);\n          }}\n          placeholder=\"From\"\n          disabled={disabled}\n        />\n        <span className=\"text-muted-foreground\">to</span>\n        <Input\n          value={rangeValue[1] || \"\"}\n          onChange={(e) => {\n            onChange([rangeValue[0] || \"\", e.target.value]);\n          }}\n          placeholder=\"To\"\n          disabled={disabled}\n        />\n      </div>\n    );\n  }\n\n  // Check if the value is a field reference (JSONPath)\n  const isFieldReference = typeof value === \"string\" && value.startsWith(\"$.\");\n\n  return (\n    <div className={cn(\"relative\", className)}>\n      <Input\n        value={value || \"\"}\n        onChange={(e) => onChange(e.target.value)}\n        placeholder={placeholder}\n        disabled={disabled}\n        className={cn(isFieldReference && \"font-mono text-xs pr-20\")}\n      />\n      {isFieldReference && (\n        <span className=\"absolute right-2 top-1/2 -translate-y-1/2 text-xs text-muted-foreground pointer-events-none\">\n          Field Ref\n        </span>\n      )}\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/VisualFieldSelector.tsx",
    "content": "import type { FieldConfig } from \"../types\";\nimport {\n  Type,\n  ToggleRight,\n  Search,\n  List,\n  Layers,\n  Hash,\n  GripVertical,\n  FileJson,\n  EyeOff,\n  Eye,\n  Copy,\n  Code2,\n  ChevronRight,\n  ChevronDown,\n  Calendar,\n  Braces,\n} from \"lucide-react\";\nimport React, { useState, useMemo, useCallback } from \"react\";\nimport { useDrop, useDrag, DndProvider } from \"react-dnd\";\nimport { HTML5Backend } from \"react-dnd-html5-backend\";\nimport { cn } from \"../lib/utils\";\nimport { JsonViewer } from \"./JsonVisualizer\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { Card } from \"./ui/card\";\nimport {\n  DialogTrigger,\n  DialogTitle,\n  DialogHeader,\n  DialogDescription,\n  DialogContent,\n  Dialog,\n} from \"./ui/dialog\";\nimport { Input } from \"./ui/input\";\nimport { Label } from \"./ui/label\";\nimport { ScrollArea } from \"./ui/scroll-area\";\nimport { TabsTrigger, TabsList, TabsContent, Tabs } from \"./ui/tabs\";\n\ninterface VisualFieldSelectorProps {\n  value: string;\n  onChange: (value: string) => void;\n  fields?: FieldConfig[];\n  sampleData?: Record<string, any>;\n  placeholder?: string;\n  disabled?: boolean;\n  className?: string;\n  allowJsonPath?: boolean;\n  showPreview?: boolean;\n}\n\ninterface FieldNode {\n  path: string;\n  name: string;\n  type: string;\n  value?: any;\n  children?: FieldNode[];\n  isArray?: boolean;\n  arrayIndex?: number;\n  depth: number;\n}\n\nconst typeIcons = {\n  string: Type,\n  number: Hash,\n  boolean: ToggleRight,\n  date: Calendar,\n  array: List,\n  object: Braces,\n  null: FileJson,\n  undefined: FileJson,\n};\n\nfunction getTypeColor(type: string) {\n  const colors = {\n    string: \"text-green-600 dark:text-green-400\",\n    number: \"text-blue-600 dark:text-blue-400\",\n    boolean: \"text-purple-600 dark:text-purple-400\",\n    date: \"text-orange-600 dark:text-orange-400\",\n    array: \"text-yellow-600 dark:text-yellow-400\",\n    object: \"text-pink-600 dark:text-pink-400\",\n    null: \"text-gray-600 dark:text-gray-400\",\n    undefined: \"text-gray-600 dark:text-gray-400\",\n  };\n  return (\n    colors[type as keyof typeof colors] || \"text-gray-600 dark:text-gray-400\"\n  );\n}\n\nconst DraggableField: React.FC<{\n  node: FieldNode;\n  onSelect: (path: string) => void;\n  selectedPath?: string;\n  searchTerm: string;\n}> = ({ node, onSelect, selectedPath, searchTerm }) => {\n  const [{ isDragging }, drag] = useDrag(\n    () => ({\n      type: \"field\",\n      item: { path: node.path, type: node.type },\n      collect: (monitor) => ({\n        isDragging: monitor.isDragging(),\n      }),\n    }),\n    [node.path, node.type],\n  );\n\n  const [expanded, setExpanded] = useState(false);\n  const hasChildren = node.children && node.children.length > 0;\n  const isSelected = selectedPath === node.path;\n\n  const matchesSearch = searchTerm\n    ? node.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n      node.path.toLowerCase().includes(searchTerm.toLowerCase())\n    : true;\n\n  if (\n    !matchesSearch &&\n    !node.children?.some(\n      (child) =>\n        child.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n        child.path.toLowerCase().includes(searchTerm.toLowerCase()),\n    )\n  ) {\n    return null;\n  }\n\n  const TypeIcon = typeIcons[node.type as keyof typeof typeIcons] || FileJson;\n\n  return (\n    <div className={cn(\"select-none\", isDragging && \"opacity-50\")}>\n      <div\n        ref={drag as any}\n        onClick={() => onSelect(node.path)}\n        className={cn(\n          \"flex items-center gap-2 px-2 py-1.5 rounded-md cursor-pointer transition-colors\",\n          \"hover:bg-accent hover:text-accent-foreground\",\n          isSelected && \"bg-primary text-primary-foreground\",\n          !matchesSearch && \"opacity-50\",\n        )}\n        style={{ paddingLeft: `${node.depth * 16 + 8}px` }}\n      >\n        <div className=\"flex items-center gap-1\">\n          {hasChildren && (\n            <Button\n              variant=\"ghost\"\n              size=\"sm\"\n              className=\"h-4 w-4 p-0\"\n              onClick={(e) => {\n                e.stopPropagation();\n                setExpanded(!expanded);\n              }}\n            >\n              {expanded ? (\n                <ChevronDown className=\"h-3 w-3\" />\n              ) : (\n                <ChevronRight className=\"h-3 w-3\" />\n              )}\n            </Button>\n          )}\n          <GripVertical className=\"h-3 w-3 text-muted-foreground\" />\n        </div>\n\n        <TypeIcon className={cn(\"h-4 w-4\", getTypeColor(node.type))} />\n\n        <span className=\"flex-1 text-sm font-medium truncate\">\n          {node.name}\n          {node.arrayIndex !== undefined && (\n            <span className=\"text-muted-foreground ml-1\">\n              [{node.arrayIndex}]\n            </span>\n          )}\n        </span>\n\n        <Badge variant=\"outline\" className=\"text-xs\">\n          {node.type}\n        </Badge>\n      </div>\n\n      {expanded && hasChildren && (\n        <div className=\"ml-2\">\n          {node.children?.map((child) => (\n            <DraggableField\n              key={child.path}\n              node={child}\n              onSelect={onSelect}\n              selectedPath={selectedPath}\n              searchTerm={searchTerm}\n            />\n          ))}\n        </div>\n      )}\n    </div>\n  );\n};\n\nfunction buildFieldTree(\n  data: any,\n  path: string = \"$\",\n  name: string = \"root\",\n  depth: number = 0,\n): FieldNode {\n  const type = Array.isArray(data) ? \"array\" : typeof data;\n  const node: FieldNode = {\n    path,\n    name,\n    type,\n    value: type === \"object\" || type === \"array\" ? undefined : data,\n    depth,\n  };\n\n  if (type === \"object\" && data !== null) {\n    node.children = Object.entries(data).map(([key, value]) => {\n      return buildFieldTree(value, `${path}.${key}`, key, depth + 1);\n    });\n  } else if (type === \"array\") {\n    node.children = data.slice(0, 10).map((item: any, index: number) => {\n      const childNode = buildFieldTree(\n        item,\n        `${path}[${index}]`,\n        `[${index}]`,\n        depth + 1,\n      );\n      childNode.arrayIndex = index;\n      childNode.isArray = true;\n      return childNode;\n    });\n    if (data.length > 10) {\n      if (!node.children) {\n        node.children = [];\n      }\n      // Add a summary node for additional items\n      node.children.push({\n        path: `${path}[*]`,\n        name: `... ${data.length - 10} more items`,\n        type: \"info\",\n        depth: depth + 1,\n      });\n    }\n  }\n\n  return node;\n}\n\nconst VisualFieldSelectorInner: React.FC<VisualFieldSelectorProps> = ({\n  value,\n  onChange,\n  fields = [],\n  sampleData,\n  placeholder = \"Select a field\",\n  disabled = false,\n  className,\n  allowJsonPath = true,\n  showPreview = true,\n}) => {\n  const [open, setOpen] = useState(false);\n  const [selectedPath, setSelectedPath] = useState(value);\n  const [searchTerm, setSearchTerm] = useState(\"\");\n  const [manualPath, setManualPath] = useState(\"\");\n  const [showValuePreview, setShowValuePreview] = useState(true);\n\n  const fieldTree = useMemo(() => {\n    if (!sampleData) {\n      return null;\n    }\n    return buildFieldTree(sampleData);\n  }, [sampleData]);\n\n  const [{ canDrop, isOver }, drop] = useDrop(\n    () => ({\n      accept: \"field\",\n      drop: (item: { path: string; type: string }) => {\n        onChange(item.path);\n        setSelectedPath(item.path);\n        setOpen(false);\n      },\n      collect: (monitor) => ({\n        isOver: monitor.isOver(),\n        canDrop: monitor.canDrop(),\n      }),\n    }),\n    [onChange],\n  );\n\n  const handleSelect = useCallback((path: string) => {\n    setSelectedPath(path);\n  }, []);\n\n  const handleConfirm = () => {\n    onChange(selectedPath);\n    setOpen(false);\n  };\n\n  const handleManualSubmit = () => {\n    onChange(manualPath);\n    setSelectedPath(manualPath);\n    setOpen(false);\n  };\n\n  const getValuePreview = useCallback(\n    (path: string) => {\n      if (!sampleData || !path) {\n        return null;\n      }\n\n      try {\n        const pathParts = path\n          .replace(\"$\", \"\")\n          .split(/[.[\\]]/)\n          .filter(Boolean);\n        let current = sampleData;\n\n        for (const part of pathParts) {\n          if (current === null || current === undefined) {\n            return null;\n          }\n\n          if (part === \"*\") {\n            return Array.isArray(current) ? \"[Array items]\" : null;\n          }\n\n          current = current[part];\n        }\n\n        return current;\n      } catch {\n        return null;\n      }\n    },\n    [sampleData],\n  );\n\n  const previewValue = getValuePreview(selectedPath);\n\n  return (\n    <Dialog open={open} onOpenChange={setOpen}>\n      <DialogTrigger asChild>\n        <div\n          ref={drop as any}\n          className={cn(\n            \"relative\",\n            canDrop && \"ring-2 ring-primary\",\n            isOver && \"ring-4\",\n            className,\n          )}\n        >\n          <Button\n            variant=\"outline\"\n            disabled={disabled}\n            className={cn(\n              \"w-full justify-between\",\n              value && \"font-mono text-xs\",\n            )}\n          >\n            {value ? (\n              <div className=\"flex items-center gap-2\">\n                <FileJson className=\"h-4 w-4\" />\n                <span className=\"truncate\">{value}</span>\n              </div>\n            ) : (\n              <span className=\"text-muted-foreground\">{placeholder}</span>\n            )}\n            <Layers className=\"h-4 w-4 ml-2\" />\n          </Button>\n          {canDrop && (\n            <div className=\"absolute inset-0 bg-primary/10 pointer-events-none rounded-md\" />\n          )}\n        </div>\n      </DialogTrigger>\n\n      <DialogContent className=\"max-w-4xl h-[80vh]\">\n        <DialogHeader>\n          <DialogTitle>Select Field</DialogTitle>\n          <DialogDescription>\n            Choose a field from the data structure or enter a custom JSON path\n          </DialogDescription>\n        </DialogHeader>\n\n        <Tabs defaultValue=\"visual\" className=\"flex-1 flex flex-col\">\n          <TabsList\n            className={cn(\n              \"grid w-full\",\n              allowJsonPath ? \"grid-cols-3\" : \"grid-cols-2\",\n            )}\n          >\n            <TabsTrigger value=\"visual\">Visual Explorer</TabsTrigger>\n            <TabsTrigger value=\"fields\">Defined Fields</TabsTrigger>\n            {allowJsonPath && (\n              <TabsTrigger value=\"manual\">Manual Entry</TabsTrigger>\n            )}\n          </TabsList>\n\n          <TabsContent value=\"visual\" className=\"flex-1 flex flex-col gap-4\">\n            <div className=\"flex items-center gap-2\">\n              <div className=\"relative flex-1\">\n                <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n                <Input\n                  placeholder=\"Search fields...\"\n                  value={searchTerm}\n                  onChange={(e) => setSearchTerm(e.target.value)}\n                  className=\"pl-9\"\n                />\n              </div>\n              {showPreview && (\n                <Button\n                  variant=\"outline\"\n                  size=\"sm\"\n                  onClick={() => setShowValuePreview(!showValuePreview)}\n                  title=\"Toggle value preview\"\n                >\n                  {showValuePreview ? (\n                    <>\n                      <Eye className=\"h-4 w-4 mr-1\" /> Hide Preview\n                    </>\n                  ) : (\n                    <>\n                      <EyeOff className=\"h-4 w-4 mr-1\" /> Show Preview\n                    </>\n                  )}\n                </Button>\n              )}\n            </div>\n\n            <div className=\"flex-1 flex gap-4 min-h-0\">\n              <Card className=\"flex-1 p-4\">\n                <ScrollArea className=\"h-full\">\n                  {fieldTree ? (\n                    <DraggableField\n                      node={fieldTree}\n                      onSelect={handleSelect}\n                      selectedPath={selectedPath}\n                      searchTerm={searchTerm}\n                    />\n                  ) : (\n                    <div className=\"text-center text-muted-foreground py-8\">\n                      No sample data available\n                    </div>\n                  )}\n                </ScrollArea>\n              </Card>\n\n              {showValuePreview && showPreview && (\n                <Card\n                  className=\"w-96 flex flex-col p-4\"\n                  style={{ maxHeight: \"500px\" }}\n                >\n                  <h4 className=\"font-medium mb-2\">Preview</h4>\n                  <div className=\"flex-1 flex flex-col gap-3 min-h-0 overflow-hidden\">\n                    <div className=\"flex-shrink-0\">\n                      <Label className=\"text-xs text-muted-foreground\">\n                        Path\n                      </Label>\n                      <div className=\"flex items-center gap-2 mt-1\">\n                        <code className=\"text-sm bg-secondary text-secondary-foreground px-2 py-1 rounded flex-1 truncate\">\n                          {selectedPath || \"No selection\"}\n                        </code>\n                        <Button\n                          variant=\"ghost\"\n                          size=\"sm\"\n                          onClick={() => {\n                            if (selectedPath) {\n                              navigator.clipboard.writeText(selectedPath);\n                            }\n                          }}\n                          disabled={!selectedPath}\n                        >\n                          <Copy className=\"h-3 w-3\" />\n                        </Button>\n                      </div>\n                    </div>\n\n                    {previewValue !== null && (\n                      <div className=\"flex-1 flex flex-col min-h-0 overflow-hidden\">\n                        <Label className=\"text-xs text-muted-foreground mb-1 flex-shrink-0\">\n                          Value\n                        </Label>\n                        <Card className=\"flex-1 overflow-hidden border-muted\">\n                          <div\n                            className=\"h-full overflow-auto scrollbar-none\"\n                            style={{\n                              scrollbarWidth: \"none\",\n                              msOverflowStyle: \"none\",\n                            }}\n                          >\n                            <div className=\"p-3\">\n                              <JsonViewer\n                                data={previewValue}\n                                rootName=\"value\"\n                                defaultExpanded={true}\n                                className=\"text-xs\"\n                              />\n                            </div>\n                          </div>\n                        </Card>\n                      </div>\n                    )}\n                  </div>\n                </Card>\n              )}\n            </div>\n\n            <div className=\"flex justify-end gap-2\">\n              <Button variant=\"outline\" onClick={() => setOpen(false)}>\n                Cancel\n              </Button>\n              <Button onClick={handleConfirm} disabled={!selectedPath}>\n                Select Field\n              </Button>\n            </div>\n          </TabsContent>\n\n          <TabsContent value=\"fields\" className=\"flex-1 flex flex-col gap-4\">\n            <ScrollArea className=\"flex-1\">\n              <div className=\"space-y-2\">\n                {fields.map((field) => (\n                  <Card\n                    key={field.name}\n                    className={cn(\n                      \"p-3 cursor-pointer transition-colors\",\n                      \"hover:bg-accent\",\n                      selectedPath === field.name &&\n                        \"bg-primary text-primary-foreground\",\n                    )}\n                    onClick={() => {\n                      setSelectedPath(field.name);\n                      onChange(field.name);\n                      setOpen(false);\n                    }}\n                  >\n                    <div className=\"flex items-center gap-2\">\n                      {React.createElement(\n                        typeIcons[field.type as keyof typeof typeIcons] ||\n                          FileJson,\n                        {\n                          className: cn(\n                            \"h-4 w-4\",\n                            getTypeColor(field.type || \"undefined\"),\n                          ),\n                        },\n                      )}\n                      <div className=\"flex-1\">\n                        <div className=\"font-medium\">\n                          {field.label || field.name}\n                        </div>\n                        {field.description && (\n                          <div className=\"text-xs text-muted-foreground\">\n                            {field.description}\n                          </div>\n                        )}\n                      </div>\n                      <Badge variant=\"outline\">{field.type}</Badge>\n                    </div>\n                  </Card>\n                ))}\n              </div>\n            </ScrollArea>\n          </TabsContent>\n\n          {allowJsonPath && (\n            <TabsContent value=\"manual\" className=\"flex-1 flex flex-col gap-4\">\n              <div className=\"space-y-4\">\n                <div>\n                  <Label>JSON Path Expression</Label>\n                  <div className=\"flex gap-2 mt-2\">\n                    <Input\n                      value={manualPath}\n                      onChange={(e) => setManualPath(e.target.value)}\n                      placeholder=\"$.user.profile.name\"\n                      className=\"font-mono\"\n                    />\n                    <Button onClick={handleManualSubmit} disabled={!manualPath}>\n                      Apply\n                    </Button>\n                  </div>\n                </div>\n\n                <div className=\"space-y-2\">\n                  <h4 className=\"font-medium text-sm\">Common Patterns</h4>\n                  <div className=\"grid grid-cols-2 gap-2\">\n                    {[\n                      { path: \"$.field\", desc: \"Root field\" },\n                      { path: \"$.parent.child\", desc: \"Nested field\" },\n                      { path: \"$.array[0]\", desc: \"Array index\" },\n                      { path: \"$.array[*]\", desc: \"All array items\" },\n                      { path: \"$..field\", desc: \"Recursive search\" },\n                      {\n                        path: \"$.array[?(@.active)]\",\n                        desc: \"Filter expression\",\n                      },\n                    ].map((example) => (\n                      <Button\n                        key={example.path}\n                        variant=\"outline\"\n                        size=\"sm\"\n                        className=\"justify-start\"\n                        onClick={() => setManualPath(example.path)}\n                      >\n                        <Code2 className=\"h-3 w-3 mr-2\" />\n                        <div className=\"text-left\">\n                          <div className=\"font-mono text-xs\">\n                            {example.path}\n                          </div>\n                          <div className=\"text-xs text-muted-foreground\">\n                            {example.desc}\n                          </div>\n                        </div>\n                      </Button>\n                    ))}\n                  </div>\n                </div>\n              </div>\n            </TabsContent>\n          )}\n        </Tabs>\n      </DialogContent>\n    </Dialog>\n  );\n};\n\nexport const VisualFieldSelector: React.FC<VisualFieldSelectorProps> = (\n  props,\n) => {\n  return (\n    <DndProvider backend={HTML5Backend}>\n      <VisualFieldSelectorInner {...props} />\n    </DndProvider>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/condition-group.tsx",
    "content": "import React from \"react\";\nimport { CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Button } from \"./ui/button\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectItem,\n  SelectContent,\n  Select,\n} from \"./ui/select\";\nimport { Label } from \"./ui/label\";\nimport { Trash2, Plus, ChevronRight, ChevronDown } from \"lucide-react\";\nimport { ConstraintEditor } from \"./ConstraintEditor\";\nimport { useRuleBuilder } from \"../stores/unified-rule-store\";\nimport { ConditionTypes } from \"@usex/rule-engine\";\nimport type { Constraint, ConditionType, Condition } from \"@usex/rule-engine\";\nimport type { ConditionGroupProps } from \"../types\";\nimport { cn } from \"../lib/utils\";\n\n// Extract default props to prevent infinite re-renders\nconst defaultFields: ConditionGroupProps[\"fields\"] = [];\nconst defaultOperators: ConditionGroupProps[\"operators\"] = [];\n\nconst isConstraint = (item: Constraint | Condition): item is Constraint => {\n  return \"field\" in item && \"operator\" in item;\n};\n\nexport const ConditionGroup: React.FC<ConditionGroupProps> = ({\n  condition,\n  path,\n  depth = 0,\n  readOnly = false,\n  fields = defaultFields,\n  operators = defaultOperators,\n  onRemove,\n  onUpdate,\n}) => {\n  const {\n    addConstraint,\n    removeConstraint,\n    addCondition,\n    updateConstraint,\n    updateCondition,\n    removeCondition,\n  } = useRuleBuilder();\n  const [collapsed, setCollapsed] = React.useState(false);\n\n  const conditionType = React.useMemo(() => {\n    if (condition.or !== undefined) return ConditionTypes.OR;\n    if (condition.and !== undefined) return ConditionTypes.AND;\n    if (condition.none !== undefined) return ConditionTypes.NONE;\n    return ConditionTypes.OR;\n  }, [condition]);\n\n  const items = React.useMemo(() => {\n    return condition[conditionType] || [];\n  }, [condition, conditionType]);\n\n  const handleConditionTypeChange = (newType: ConditionType) => {\n    if (newType === conditionType) return;\n\n    // Create a clean condition object with only the new type and items\n    const newCondition: Condition = {\n      [newType]: items,\n    };\n\n    // Add result if it exists\n    if (condition.result !== undefined) {\n      newCondition.result = condition.result;\n    }\n\n    // Use onUpdate callback if provided, otherwise fallback to store method\n    if (onUpdate) {\n      onUpdate(newCondition);\n    } else {\n      updateCondition(path, newCondition);\n    }\n  };\n\n  const handleAddConstraint = () => {\n    const newConstraint: Constraint = {\n      field: \"\",\n      operator: \"equals\" as any,\n      value: \"\",\n    };\n    // Add constraint to this condition group by appending the condition type to the path\n    const constraintPath = path ? `${path}.${conditionType}` : conditionType;\n    addConstraint(constraintPath, newConstraint);\n  };\n\n  const handleAddConditionGroup = () => {\n    // Add new condition group to this condition group by appending the condition type to the path\n    const parentPath = path ? `${path}.${conditionType}` : conditionType;\n    addCondition(parentPath, ConditionTypes.AND);\n  };\n\n  const handleUpdateItem = (index: number, item: Constraint | Condition) => {\n    if (isConstraint(item)) {\n      // Update constraint directly through store\n      const itemPath = path\n        ? `${path}.${conditionType}.${index}`\n        : `${conditionType}.${index}`;\n      updateConstraint(itemPath, item);\n    } else {\n      // Update condition directly through store\n      const itemPath = path\n        ? `${path}.${conditionType}.${index}`\n        : `${conditionType}.${index}`;\n      updateCondition(itemPath, item);\n    }\n  };\n\n  const handleRemoveItem = (index: number) => {\n    if (isConstraint(items[index])) {\n      // Remove constraint using store function\n      const itemPath = path\n        ? `${path}.${conditionType}.${index}`\n        : `${conditionType}.${index}`;\n      removeConstraint(itemPath);\n    } else {\n      // Remove condition using store function\n      const itemPath = path\n        ? `${path}.${conditionType}.${index}`\n        : `${conditionType}.${index}`;\n      removeCondition(itemPath);\n    }\n  };\n\n  const conditionTypeColor = {\n    [ConditionTypes.OR]:\n      \"text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-950/30 border-blue-200 dark:border-blue-800\",\n    [ConditionTypes.AND]:\n      \"text-green-600 dark:text-green-400 bg-green-50 dark:bg-green-950/30 border-green-200 dark:border-green-800\",\n    [ConditionTypes.NONE]:\n      \"text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-950/30 border-red-200 dark:border-red-800\",\n  };\n\n  return (\n    <Card\n      className={cn(\n        \"rounded-lg shadow-sm border-2\",\n        conditionTypeColor[conditionType],\n        depth > 0 && \"ml-8\",\n      )}\n    >\n      <CardHeader className=\"p-4\">\n        <div className=\"flex items-center justify-between\">\n          <div className=\"flex items-center gap-4\">\n            <Button\n              type=\"button\"\n              variant=\"ghost\"\n              size=\"sm\"\n              onClick={() => setCollapsed(!collapsed)}\n              className=\"p-0 h-auto\"\n            >\n              {collapsed ? (\n                <ChevronRight className=\"h-4 w-4\" />\n              ) : (\n                <ChevronDown className=\"h-4 w-4\" />\n              )}\n            </Button>\n\n            <div className=\"flex items-center gap-2\">\n              <Label className=\"text-gray-900 dark:text-gray-100 font-medium\">\n                Condition Type:\n              </Label>\n              <Select\n                value={conditionType}\n                onValueChange={handleConditionTypeChange}\n                disabled={readOnly}\n              >\n                <SelectTrigger className=\"w-[100px]\">\n                  <SelectValue />\n                </SelectTrigger>\n                <SelectContent>\n                  <SelectItem value={ConditionTypes.OR}>OR</SelectItem>\n                  <SelectItem value={ConditionTypes.AND}>AND</SelectItem>\n                  <SelectItem value={ConditionTypes.NONE}>NONE</SelectItem>\n                </SelectContent>\n              </Select>\n            </div>\n          </div>\n\n          <div className=\"flex items-center gap-2\">\n            {!readOnly && (\n              <>\n                <Button\n                  type=\"button\"\n                  variant=\"outline\"\n                  size=\"sm\"\n                  onClick={handleAddConstraint}\n                >\n                  <Plus className=\"h-4 w-4 mr-2\" />\n                  Add Rule\n                </Button>\n                <Button\n                  type=\"button\"\n                  variant=\"outline\"\n                  size=\"sm\"\n                  onClick={handleAddConditionGroup}\n                >\n                  <Plus className=\"h-4 w-4 mr-2\" />\n                  Add Group\n                </Button>\n              </>\n            )}\n            {!readOnly && onRemove && depth > 0 && (\n              <Button\n                type=\"button\"\n                variant=\"ghost\"\n                size=\"icon\"\n                onClick={onRemove}\n              >\n                <Trash2 className=\"h-4 w-4\" />\n              </Button>\n            )}\n          </div>\n        </div>\n      </CardHeader>\n\n      {!collapsed && (\n        <CardContent className=\"p-4 pt-0 space-y-4\">\n          {items.length === 0 ? (\n            <div className=\"text-center text-muted-foreground py-8\">\n              No rules in this group. Add a rule or condition group to get\n              started.\n            </div>\n          ) : (\n            items.map((item, index) => {\n              const itemPath = path\n                ? `${path}.${conditionType}.${index}`\n                : `${conditionType}.${index}`;\n\n              if (isConstraint(item)) {\n                return (\n                  <ConstraintEditor\n                    key={itemPath}\n                    constraint={item}\n                    path={itemPath}\n                    fields={fields}\n                    operators={operators}\n                    readOnly={readOnly}\n                    onUpdate={(constraint) =>\n                      updateConstraint(itemPath, constraint)\n                    }\n                    onRemove={() => handleRemoveItem(index)}\n                  />\n                );\n              } else {\n                return (\n                  <ConditionGroup\n                    key={itemPath}\n                    condition={item}\n                    path={itemPath}\n                    depth={depth + 1}\n                    fields={fields}\n                    operators={operators}\n                    readOnly={readOnly}\n                    onUpdate={(condition) => handleUpdateItem(index, condition)}\n                    onRemove={() => handleRemoveItem(index)}\n                  />\n                );\n              }\n            })\n          )}\n        </CardContent>\n      )}\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/editable-json-viewer.tsx",
    "content": "import type { RuleType, EvaluationResult } from \"@usex/rule-engine\";\nimport { RuleEngine } from \"@usex/rule-engine\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Zap,\n  XCircle,\n  X,\n  Upload,\n  Save,\n  Play,\n  Minimize2,\n  Maximize2,\n  Info,\n  Edit2,\n  Download,\n  Copy,\n  CheckCircle2,\n  Check,\n  AlertCircle,\n  Activity,\n} from \"lucide-react\";\nimport React, { useState, useMemo, useEffect, useCallback } from \"react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"../lib/utils\";\nimport { JsonViewer } from \"./JsonVisualizer\";\nimport { AlertDescription, Alert } from \"./ui/alert\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Label } from \"./ui/label\";\nimport { Separator } from \"./ui/separator\";\nimport { Switch } from \"./ui/switch\";\nimport { Textarea } from \"./ui/textarea\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"./ui/tooltip\";\n\ninterface EditableJsonViewerProps {\n  rule: RuleType;\n  className?: string;\n  onUpdate?: (rule: RuleType) => void;\n  onImport?: (rule: RuleType) => void;\n  expanded?: boolean;\n  onExpandedChange?: (expanded: boolean) => void;\n  readOnly?: boolean;\n  sampleData?: any;\n  showEvaluator?: boolean;\n}\n\nexport const EditableJsonViewer: React.FC<EditableJsonViewerProps> = ({\n  rule,\n  className,\n  onUpdate,\n  onImport,\n  expanded = false,\n  onExpandedChange,\n  readOnly = false,\n  sampleData,\n  showEvaluator = true,\n}) => {\n  const [copied, setCopied] = useState(false);\n  const [isEditing, setIsEditing] = useState(false);\n  const [editedJson, setEditedJson] = useState(\"\");\n  const [error, setError] = useState<string | null>(null);\n  const fileInputRef = React.useRef<HTMLInputElement>(null);\n\n  // Evaluator state\n  const [isLiveMode, setIsLiveMode] = useState(false);\n  const [evaluationResult, setEvaluationResult] =\n    useState<EvaluationResult | null>(null);\n  const [isEvaluating, setIsEvaluating] = useState(false);\n\n  const jsonString = useMemo(() => {\n    return JSON.stringify(rule, null, 2);\n  }, [rule]);\n\n  const handleCopy = async () => {\n    try {\n      await navigator.clipboard.writeText(jsonString);\n      setCopied(true);\n      setTimeout(() => setCopied(false), 2000);\n      toast.success(\"JSON copied to clipboard\");\n    } catch (error) {\n      console.error(\"Failed to copy:\", error);\n      toast.error(\"Failed to copy JSON\");\n    }\n  };\n\n  const handleExport = () => {\n    const blob = new Blob([jsonString], { type: \"application/json\" });\n    const url = URL.createObjectURL(blob);\n    const a = document.createElement(\"a\");\n    a.href = url;\n    a.download = `rule-${Date.now()}.json`;\n    document.body.appendChild(a);\n    a.click();\n    document.body.removeChild(a);\n    URL.revokeObjectURL(url);\n    toast.success(\"Rule exported successfully\");\n  };\n\n  const handleImport = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const file = event.target.files?.[0];\n    if (!file || !onImport) return;\n\n    const reader = new FileReader();\n    reader.onload = (e) => {\n      try {\n        const content = e.target?.result as string;\n        const importedRule: RuleType = JSON.parse(content);\n        onImport(importedRule);\n        toast.success(\"Rule imported successfully\");\n      } catch (error) {\n        console.error(\"Failed to import rule:\", error);\n        toast.error(\"Failed to import rule: Invalid JSON\");\n      }\n    };\n    reader.readAsText(file);\n\n    if (fileInputRef.current) {\n      fileInputRef.current.value = \"\";\n    }\n  };\n\n  const handleSaveEdit = () => {\n    try {\n      const parsedRule = JSON.parse(editedJson) as RuleType;\n\n      // Basic validation\n      if (!parsedRule.conditions) {\n        throw new Error(\"Rule must have conditions\");\n      }\n\n      if (onUpdate) {\n        onUpdate(parsedRule);\n        setIsEditing(false);\n        setError(null);\n        toast.success(\"Rule updated successfully\");\n      }\n    } catch (err) {\n      const errorMessage = err instanceof Error ? err.message : \"Invalid JSON\";\n      setError(errorMessage);\n      toast.error(`Failed to update rule: ${errorMessage}`);\n    }\n  };\n\n  const handleStartEdit = () => {\n    setEditedJson(jsonString);\n    setIsEditing(true);\n  };\n\n  const handleCancelEdit = () => {\n    setIsEditing(false);\n    setEditedJson(\"\");\n    setError(null);\n  };\n\n  const lineCount = jsonString.split(\"\\n\").length;\n\n  // Evaluate rule function\n  const evaluateRule = useCallback(async () => {\n    if (!rule || !rule.conditions || !sampleData) {\n      return;\n    }\n\n    setIsEvaluating(true);\n\n    try {\n      const result = await RuleEngine.evaluate(rule, sampleData);\n      const evalResult = Array.isArray(result) ? result[0] : result;\n      setEvaluationResult(evalResult);\n    } catch {\n      setEvaluationResult(null);\n    } finally {\n      setIsEvaluating(false);\n    }\n  }, [rule, sampleData]);\n\n  // Live evaluation effect\n  useEffect(() => {\n    if (isLiveMode && showEvaluator) {\n      evaluateRule();\n    }\n  }, [isLiveMode, rule, sampleData, evaluateRule, showEvaluator]);\n\n  // Keyboard shortcuts\n  useEffect(() => {\n    if (!showEvaluator || !sampleData) return;\n\n    const handleKeyDown = (e: KeyboardEvent) => {\n      const isMac = navigator.userAgent.toUpperCase().includes(\"MAC\");\n      const ctrlOrCmd = isMac ? e.metaKey : e.ctrlKey;\n\n      // Toggle live mode: Ctrl/Cmd + E\n      if (ctrlOrCmd && e.key === \"e\" && !e.shiftKey) {\n        e.preventDefault();\n        setIsLiveMode((prev) => !prev);\n      }\n\n      // Run evaluation once: Ctrl/Cmd + Shift + E\n      if (ctrlOrCmd && e.shiftKey && e.key === \"E\") {\n        e.preventDefault();\n        if (!isLiveMode) {\n          evaluateRule();\n        }\n      }\n    };\n\n    window.addEventListener(\"keydown\", handleKeyDown);\n    return () => window.removeEventListener(\"keydown\", handleKeyDown);\n  }, [showEvaluator, sampleData, isLiveMode, evaluateRule]);\n\n  return (\n    <Card className={cn(\"overflow-hidden\", className)}>\n      <CardHeader className=\"space-y-0\">\n        {/* Evaluator Row */}\n        {showEvaluator && sampleData && (\n          <>\n            <div className=\"flex items-center justify-between py-2\">\n              <div className=\"flex items-center gap-3\">\n                <Activity className=\"h-4 w-4 text-muted-foreground\" />\n                <span className=\"text-sm font-medium\">Rule Evaluation</span>\n                <TooltipProvider>\n                  <Tooltip>\n                    <TooltipTrigger asChild>\n                      <Info className=\"h-3 w-3 text-muted-foreground cursor-help\" />\n                    </TooltipTrigger>\n                    <TooltipContent side=\"bottom\" className=\"max-w-xs\">\n                      <div className=\"space-y-2\">\n                        <p className=\"text-sm\">\n                          Evaluate your rule against sample data in real-time\n                        </p>\n                        <div className=\"space-y-1 text-xs\">\n                          <div className=\"flex items-center gap-2\">\n                            <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-xs font-mono\">\n                              Ctrl/Cmd + E\n                            </kbd>\n                            <span>Toggle live mode</span>\n                          </div>\n                          <div className=\"flex items-center gap-2\">\n                            <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-xs font-mono\">\n                              Ctrl/Cmd + Shift + E\n                            </kbd>\n                            <span>Run once</span>\n                          </div>\n                        </div>\n                      </div>\n                    </TooltipContent>\n                  </Tooltip>\n                </TooltipProvider>\n                {isEvaluating && (\n                  <motion.div\n                    animate={{ rotate: 360 }}\n                    transition={{\n                      duration: 1,\n                      repeat: Infinity,\n                      ease: \"linear\",\n                    }}\n                  >\n                    <Zap className=\"h-3 w-3 text-yellow-500\" />\n                  </motion.div>\n                )}\n                {evaluationResult && (\n                  <AnimatePresence mode=\"wait\">\n                    <motion.div\n                      key={evaluationResult.isPassed ? \"pass\" : \"fail\"}\n                      initial={{ scale: 0 }}\n                      animate={{ scale: 1 }}\n                      exit={{ scale: 0 }}\n                      transition={{\n                        type: \"spring\",\n                        stiffness: 500,\n                        damping: 30,\n                      }}\n                      className={cn(\n                        \"flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium\",\n                        evaluationResult.isPassed\n                          ? \"bg-green-500/20 text-green-600\"\n                          : \"bg-red-500/20 text-red-600\",\n                      )}\n                    >\n                      {evaluationResult.isPassed ? (\n                        <>\n                          <CheckCircle2 className=\"h-3 w-3\" />\n                          <span>Pass</span>\n                        </>\n                      ) : (\n                        <>\n                          <XCircle className=\"h-3 w-3\" />\n                          <span>Fail</span>\n                        </>\n                      )}\n                    </motion.div>\n                  </AnimatePresence>\n                )}\n              </div>\n              <div className=\"flex items-center gap-3\">\n                <div className=\"flex items-center gap-2\">\n                  <Label\n                    htmlFor=\"live-eval\"\n                    className=\"text-xs cursor-pointer select-none\"\n                  >\n                    Live\n                  </Label>\n                  <Switch\n                    id=\"live-eval\"\n                    checked={isLiveMode}\n                    onCheckedChange={setIsLiveMode}\n                    className=\"data-[state=checked]:bg-primary\"\n                  />\n                </div>\n                {!isLiveMode && (\n                  <Button\n                    variant=\"ghost\"\n                    size=\"sm\"\n                    onClick={evaluateRule}\n                    disabled={isEvaluating}\n                    className=\"h-7 px-2 text-xs\"\n                  >\n                    <Play className=\"h-3 w-3 mr-1\" />\n                    Evaluate\n                  </Button>\n                )}\n              </div>\n            </div>\n            <Separator className=\"mb-3\" />\n          </>\n        )}\n\n        {/* Original Header */}\n        <div className=\"flex flex-row items-center justify-between pb-3\">\n          <div className=\"flex items-center gap-2\">\n            <CardTitle className=\"text-base font-medium\">Rule JSON</CardTitle>\n            <Badge variant=\"secondary\" className=\"text-xs\">\n              {lineCount} lines\n            </Badge>\n            {isEditing && (\n              <Badge variant=\"destructive\" className=\"text-xs\">\n                Editing\n              </Badge>\n            )}\n          </div>\n          <div className=\"flex items-center gap-1\">\n            {!isEditing && (\n              <>\n                {onImport && (\n                  <>\n                    <input\n                      ref={fileInputRef}\n                      type=\"file\"\n                      accept=\".json,application/json\"\n                      onChange={handleImport}\n                      className=\"hidden\"\n                    />\n                    <Button\n                      variant=\"ghost\"\n                      size=\"icon\"\n                      className=\"h-8 w-8\"\n                      onClick={() => fileInputRef.current?.click()}\n                      title=\"Import JSON\"\n                    >\n                      <Upload className=\"h-4 w-4\" />\n                    </Button>\n                  </>\n                )}\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"h-8 w-8\"\n                  onClick={handleExport}\n                  title=\"Export JSON\"\n                >\n                  <Download className=\"h-4 w-4\" />\n                </Button>\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"h-8 w-8\"\n                  onClick={handleCopy}\n                  title=\"Copy JSON\"\n                >\n                  {copied ? (\n                    <Check className=\"h-4 w-4 text-green-600\" />\n                  ) : (\n                    <Copy className=\"h-4 w-4\" />\n                  )}\n                </Button>\n                {!readOnly && onUpdate && (\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    className=\"h-8 w-8\"\n                    onClick={handleStartEdit}\n                    title=\"Edit JSON\"\n                  >\n                    <Edit2 className=\"h-4 w-4\" />\n                  </Button>\n                )}\n              </>\n            )}\n            {isEditing && (\n              <>\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"h-8 w-8 text-green-600 hover:text-green-700\"\n                  onClick={handleSaveEdit}\n                  title=\"Save changes\"\n                >\n                  <Save className=\"h-4 w-4\" />\n                </Button>\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"h-8 w-8 text-destructive hover:text-destructive\"\n                  onClick={handleCancelEdit}\n                  title=\"Cancel editing\"\n                >\n                  <X className=\"h-4 w-4\" />\n                </Button>\n              </>\n            )}\n            {onExpandedChange && (\n              <Button\n                variant=\"ghost\"\n                size=\"icon\"\n                className=\"h-8 w-8\"\n                onClick={() => onExpandedChange(!expanded)}\n                title={expanded ? \"Minimize\" : \"Maximize\"}\n              >\n                {expanded ? (\n                  <Minimize2 className=\"h-4 w-4\" />\n                ) : (\n                  <Maximize2 className=\"h-4 w-4\" />\n                )}\n              </Button>\n            )}\n          </div>\n        </div>\n      </CardHeader>\n      <CardContent className=\"p-0\">\n        {error && (\n          <Alert variant=\"destructive\" className=\"mx-4 mb-2\">\n            <AlertCircle className=\"h-4 w-4\" />\n            <AlertDescription>{error}</AlertDescription>\n          </Alert>\n        )}\n        <div\n          className={cn(\n            \"overflow-auto\",\n            expanded ? \"max-h-[80vh]\" : \"max-h-[400px]\",\n          )}\n        >\n          {isEditing ? (\n            <Textarea\n              value={editedJson}\n              onChange={(e) => {\n                setEditedJson(e.target.value);\n                setError(null);\n              }}\n              className=\"min-h-[400px] font-mono text-sm border-0 focus-visible:ring-0 resize-none rounded-none\"\n              style={{ minHeight: expanded ? \"70vh\" : \"400px\" }}\n              placeholder=\"Enter valid JSON...\"\n            />\n          ) : (\n            <div className=\"p-4\">\n              <JsonViewer\n                data={rule}\n                rootName=\"rule\"\n                defaultExpanded={true}\n                className=\"max-w-full\"\n                highlightLogicalOperators={true}\n              />\n            </div>\n          )}\n        </div>\n      </CardContent>\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/history-viewer.tsx",
    "content": "import type { HistoryEntry } from \"../stores/unified-rule-store\";\nimport { formatDistanceToNow, format } from \"date-fns\";\nimport {\n  XCircle,\n  Search,\n  RotateCcw,\n  GitBranch,\n  Eye,\n  Clock,\n  CheckCircle,\n  ArrowRight,\n  ArrowLeft,\n} from \"lucide-react\";\nimport React, { useState, useMemo } from \"react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"../lib/utils\";\nimport { useUnifiedRuleStore } from \"../stores/unified-rule-store\";\nimport { DiffViewer } from \"./DiffViewer\";\nimport { JsonViewer } from \"./JsonVisualizer\";\nimport { ResizablePanel } from \"./ResizablePanel\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Input } from \"./ui/input\";\nimport { ScrollArea } from \"./ui/scroll-area\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectItem,\n  SelectContent,\n  Select,\n} from \"./ui/select\";\nimport { TabsTrigger, TabsList, TabsContent, Tabs } from \"./ui/tabs\";\nimport {\n  ZoomDialogTitle,\n  ZoomDialogHeader,\n  ZoomDialogDescription,\n  ZoomDialogContent,\n  ZoomDialog,\n} from \"./ui/zoom-dialog\";\n\ninterface HistoryViewerProps {\n  className?: string;\n}\n\nexport const HistoryViewer: React.FC<HistoryViewerProps> = ({ className }) => {\n  const [open, setOpen] = useState(false);\n  const [searchTerm, setSearchTerm] = useState(\"\");\n  const [filterAction, setFilterAction] = useState<string>(\"all\");\n  const [selectedEntry, setSelectedEntry] = useState<HistoryEntry | null>(null);\n  const [compareEntry, setCompareEntry] = useState<HistoryEntry | null>(null);\n\n  const store = useUnifiedRuleStore();\n  const historyInfo = store.getHistoryInfo();\n  const { entries: history, current: historyIndex } = historyInfo;\n  const { setRule, canUndo, canRedo, undo, redo } = store;\n\n  // Filter history entries\n  const filteredHistory = useMemo(() => {\n    return history.filter((entry: HistoryEntry) => {\n      const matchesSearch = searchTerm\n        ? entry.description.toLowerCase().includes(searchTerm.toLowerCase()) ||\n          entry.action.toLowerCase().includes(searchTerm.toLowerCase())\n        : true;\n\n      const matchesFilter =\n        filterAction === \"all\" || entry.action === filterAction;\n\n      return matchesSearch && matchesFilter;\n    });\n  }, [history, searchTerm, filterAction]);\n\n  // Get unique actions for filter\n  const uniqueActions = useMemo(() => {\n    const actions = new Set(history.map((entry: HistoryEntry) => entry.action));\n    return [\"all\", ...Array.from(actions)];\n  }, [history]);\n\n  const handleCheckout = (entry: HistoryEntry, index: number) => {\n    setRule(\n      entry.rule,\n      \"Checkout\",\n      `Checked out to version from ${format(entry.timestamp, \"PPp\")}`,\n    );\n    toast.success(`Checked out to version ${index + 1}`);\n    setOpen(false);\n  };\n\n  const getActionIcon = (action: string) => {\n    switch (action.toLowerCase()) {\n      case \"add\":\n      case \"create\":\n        return <CheckCircle className=\"h-4 w-4 text-green-500\" />;\n      case \"remove\":\n      case \"delete\":\n        return <XCircle className=\"h-4 w-4 text-red-500\" />;\n      case \"update\":\n      case \"edit\":\n        return <GitBranch className=\"h-4 w-4 text-blue-500\" />;\n      default:\n        return <Clock className=\"h-4 w-4 text-gray-500\" />;\n    }\n  };\n\n  return (\n    <>\n      <Button\n        variant=\"ghost\"\n        size=\"sm\"\n        onClick={() => setOpen(true)}\n        className={cn(\"gap-2 rounded-md\", className)}\n      >\n        <Clock className=\"h-4 w-4\" />\n        History\n      </Button>\n\n      <ZoomDialog open={open} onOpenChange={setOpen}>\n        <ZoomDialogContent className=\"max-w-6xl h-[90vh] flex flex-col overflow-hidden shadow-lg rounded-lg\">\n          <ZoomDialogHeader className=\"shrink-0 border-b p-6\">\n            <div className=\"flex items-center gap-3\">\n              <div className=\"p-2 rounded-md bg-primary/10\">\n                <Clock className=\"h-5 w-5 text-primary\" />\n              </div>\n              <div>\n                <ZoomDialogTitle className=\"text-xl font-semibold\">\n                  Version History\n                </ZoomDialogTitle>\n                <ZoomDialogDescription className=\"text-muted-foreground\">\n                  View and manage the history of changes to your rule\n                </ZoomDialogDescription>\n              </div>\n            </div>\n          </ZoomDialogHeader>\n\n          <div className=\"flex-1 flex flex-col gap-6 overflow-hidden p-0 pt-4\">\n            {/* Controls */}\n            <div className=\"flex items-center gap-4\">\n              <div className=\"relative flex-1\">\n                <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n                <Input\n                  placeholder=\"Search history...\"\n                  value={searchTerm}\n                  onChange={(e) => setSearchTerm(e.target.value)}\n                  className=\"pl-9 rounded-md\"\n                />\n              </div>\n              <Select value={filterAction} onValueChange={setFilterAction}>\n                <SelectTrigger className=\"w-[180px] rounded-md\">\n                  <SelectValue placeholder=\"Filter actions\" />\n                </SelectTrigger>\n                <SelectContent className=\"rounded-md\">\n                  {uniqueActions.map((action: string) => (\n                    <SelectItem\n                      key={action}\n                      value={action}\n                      className=\"rounded-md\"\n                    >\n                      {action === \"all\" ? \"All Actions\" : action}\n                    </SelectItem>\n                  ))}\n                </SelectContent>\n              </Select>\n              <div className=\"flex items-center gap-2\">\n                <Button\n                  variant=\"outline\"\n                  size=\"icon\"\n                  onClick={undo}\n                  disabled={!canUndo()}\n                  title=\"Undo\"\n                  className=\"rounded-md\"\n                >\n                  <ArrowLeft className=\"h-4 w-4\" />\n                </Button>\n                <Button\n                  variant=\"outline\"\n                  size=\"icon\"\n                  onClick={redo}\n                  disabled={!canRedo()}\n                  title=\"Redo\"\n                  className=\"rounded-md\"\n                >\n                  <ArrowRight className=\"h-4 w-4\" />\n                </Button>\n              </div>\n            </div>\n\n            {/* History List and Details */}\n            <div className=\"flex-1 min-h-0 overflow-hidden\">\n              <ResizablePanel\n                defaultSize={35}\n                minSize={25}\n                maxSize={50}\n                direction=\"horizontal\"\n                persistId=\"history-panel\"\n                className=\"h-full\"\n                handleClassName=\"mx-2\"\n              >\n                {/* History List */}\n                <Card className=\"h-full flex flex-col overflow-hidden rounded-lg shadow-sm border\">\n                  <CardHeader className=\"py-4 px-6 shrink-0 bg-muted/30 border-b\">\n                    <CardTitle className=\"text-lg font-semibold flex items-center gap-2\">\n                      <GitBranch className=\"h-5 w-5 text-primary\" />\n                      History ({filteredHistory.length} entries)\n                    </CardTitle>\n                  </CardHeader>\n                  <CardContent className=\"flex-1 p-0 overflow-hidden\">\n                    <ScrollArea className=\"h-full\">\n                      <div className=\"p-4 space-y-2\">\n                        {filteredHistory.map((entry) => {\n                          const actualIndex = history.indexOf(entry);\n                          const isCurrent = actualIndex === historyIndex;\n                          const isPast = actualIndex < historyIndex;\n\n                          return (\n                            <Card\n                              key={entry.timestamp}\n                              className={cn(\n                                \"group p-4 cursor-pointer transition-all duration-200 rounded-md border\",\n                                \"hover:shadow-md hover:scale-[1.01]\",\n                                isCurrent && \"ring-2 ring-primary bg-primary/5\",\n                                selectedEntry === entry &&\n                                  \"bg-accent ring-1 ring-accent-foreground/20\",\n                                !isCurrent &&\n                                  !selectedEntry &&\n                                  \"bg-card hover:bg-accent/50\",\n                                isPast && \"opacity-70\",\n                              )}\n                              onClick={() => setSelectedEntry(entry)}\n                            >\n                              <div className=\"flex items-start gap-3\">\n                                {getActionIcon(entry.action)}\n                                <div className=\"flex-1 min-w-0\">\n                                  <div className=\"flex items-center gap-2\">\n                                    <h4 className=\"font-semibold text-sm truncate\">\n                                      {entry.action}\n                                    </h4>\n                                    {isCurrent && (\n                                      <Badge\n                                        className=\"text-xs\"\n                                        variant=\"secondary\"\n                                      >\n                                        Current\n                                      </Badge>\n                                    )}\n                                  </div>\n                                  <p className=\"text-xs text-muted-foreground truncate mt-1\">\n                                    {entry.description}\n                                  </p>\n                                  <div className=\"flex items-center gap-2 mt-2\">\n                                    <span className=\"text-xs text-muted-foreground font-medium\">\n                                      {formatDistanceToNow(entry.timestamp, {\n                                        addSuffix: true,\n                                      })}\n                                    </span>\n                                    <span className=\"text-xs text-muted-foreground/50\">\n                                      •\n                                    </span>\n                                    <span className=\"text-xs font-mono bg-muted px-2 py-0.5 rounded\">\n                                      v{actualIndex + 1}\n                                    </span>\n                                  </div>\n                                </div>\n                                <div className=\"flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity\">\n                                  <Button\n                                    variant=\"ghost\"\n                                    size=\"sm\"\n                                    onClick={(e) => {\n                                      e.stopPropagation();\n                                      handleCheckout(entry, actualIndex);\n                                    }}\n                                    disabled={isCurrent}\n                                    title=\"Checkout this version\"\n                                    className=\"h-8 w-8 p-0 rounded-md hover:bg-accent\"\n                                  >\n                                    <RotateCcw className=\"h-3 w-3\" />\n                                  </Button>\n                                  <Button\n                                    variant=\"ghost\"\n                                    size=\"sm\"\n                                    onClick={(e) => {\n                                      e.stopPropagation();\n                                      setCompareEntry(\n                                        entry === compareEntry ? null : entry,\n                                      );\n                                    }}\n                                    title=\"Compare with selected\"\n                                    className=\"h-8 w-8 p-0 rounded-md hover:bg-accent\"\n                                  >\n                                    <Eye className=\"h-3 w-3\" />\n                                  </Button>\n                                </div>\n                              </div>\n                            </Card>\n                          );\n                        })}\n                      </div>\n                    </ScrollArea>\n                  </CardContent>\n                </Card>\n\n                {/* Details/Diff View */}\n                <Card className=\"h-full flex flex-col overflow-hidden rounded-lg shadow-sm border\">\n                  <CardHeader className=\"py-4 px-6 shrink-0 bg-muted/30 border-b\">\n                    <CardTitle className=\"text-lg font-semibold flex items-center gap-2\">\n                      <Eye className=\"h-5 w-5 text-primary\" />\n                      Version Details\n                    </CardTitle>\n                  </CardHeader>\n                  <CardContent className=\"flex-1 p-0 overflow-hidden\">\n                    {selectedEntry ? (\n                      <Tabs\n                        defaultValue=\"details\"\n                        className=\"h-full flex flex-col overflow-hidden\"\n                      >\n                        <TabsList className=\"m-4 mb-0 shrink-0 bg-muted/50 p-1 rounded-lg\">\n                          <TabsTrigger\n                            value=\"details\"\n                            className=\"flex items-center gap-2 rounded-md data-[state=active]:bg-background data-[state=active]:shadow-sm transition-all\"\n                          >\n                            <Eye className=\"h-4 w-4\" />\n                            Details\n                          </TabsTrigger>\n                          <TabsTrigger\n                            value=\"changes\"\n                            className=\"flex items-center gap-2 rounded-md data-[state=active]:bg-background data-[state=active]:shadow-sm transition-all\"\n                          >\n                            <GitBranch className=\"h-4 w-4\" />\n                            Changes\n                          </TabsTrigger>\n                          <TabsTrigger\n                            value=\"json\"\n                            className=\"flex items-center gap-2 rounded-md data-[state=active]:bg-background data-[state=active]:shadow-sm transition-all\"\n                          >\n                            <ArrowRight className=\"h-4 w-4\" />\n                            JSON\n                          </TabsTrigger>\n                          {compareEntry && (\n                            <TabsTrigger\n                              value=\"compare\"\n                              className=\"flex items-center gap-2 rounded-md data-[state=active]:bg-background data-[state=active]:shadow-sm transition-all\"\n                            >\n                              <ArrowLeft className=\"h-4 w-4\" />\n                              Compare\n                            </TabsTrigger>\n                          )}\n                        </TabsList>\n\n                        <TabsContent\n                          value=\"details\"\n                          className=\"flex-1 overflow-auto p-0\"\n                        >\n                          <div className=\"space-y-6 p-6\">\n                            <div className=\"bg-accent/50 p-5 rounded-lg border\">\n                              <div className=\"flex items-center gap-3 mb-4\">\n                                <div className=\"p-2 rounded-md bg-primary/10\">\n                                  <CheckCircle className=\"h-5 w-5 text-primary\" />\n                                </div>\n                                <h4 className=\"font-semibold text-lg\">\n                                  Version Information\n                                </h4>\n                              </div>\n                              <div className=\"grid grid-cols-1 gap-4\">\n                                <div className=\"flex justify-between items-center p-3 bg-background rounded-md border\">\n                                  <span className=\"text-sm font-medium text-muted-foreground\">\n                                    Version:\n                                  </span>\n                                  <span className=\"text-sm font-mono bg-primary/10 text-primary px-2 py-1 rounded\">\n                                    v{history.indexOf(selectedEntry) + 1}\n                                  </span>\n                                </div>\n                                <div className=\"flex justify-between items-center p-3 bg-background rounded-md border\">\n                                  <span className=\"text-sm font-medium text-muted-foreground\">\n                                    Action:\n                                  </span>\n                                  <div className=\"flex items-center gap-2\">\n                                    {getActionIcon(selectedEntry.action)}\n                                    <span className=\"text-sm font-medium\">\n                                      {selectedEntry.action}\n                                    </span>\n                                  </div>\n                                </div>\n                                <div className=\"flex justify-between items-center p-3 bg-background rounded-md border\">\n                                  <span className=\"text-sm font-medium text-muted-foreground\">\n                                    Time:\n                                  </span>\n                                  <span className=\"text-sm font-mono\">\n                                    {format(selectedEntry.timestamp, \"PPp\")}\n                                  </span>\n                                </div>\n                              </div>\n                            </div>\n\n                            <div className=\"bg-muted/50 p-5 rounded-lg border\">\n                              <div className=\"flex items-center gap-3 mb-4\">\n                                <div className=\"p-2 rounded-md bg-muted\">\n                                  <ArrowRight className=\"h-5 w-5 text-muted-foreground\" />\n                                </div>\n                                <h4 className=\"font-semibold text-lg\">\n                                  Description\n                                </h4>\n                              </div>\n                              <div className=\"p-4 bg-background rounded-md border\">\n                                <p className=\"text-sm leading-relaxed\">\n                                  {selectedEntry.description}\n                                </p>\n                              </div>\n                            </div>\n                          </div>\n                        </TabsContent>\n\n                        <TabsContent\n                          value=\"changes\"\n                          className=\"flex-1 overflow-hidden p-0\"\n                        >\n                          <div className=\"h-full p-6\">\n                            {selectedEntry.changes ? (\n                              <div className=\"h-full bg-card rounded-lg border overflow-hidden\">\n                                <DiffViewer\n                                  oldValue={selectedEntry.changes.before}\n                                  newValue={selectedEntry.changes.after}\n                                  oldTitle=\"Before\"\n                                  newTitle=\"After\"\n                                  title=\"Changes\"\n                                  className=\"h-full rounded-lg\"\n                                />\n                              </div>\n                            ) : (\n                              <div className=\"h-full flex items-center justify-center\">\n                                <div className=\"text-center space-y-4\">\n                                  <div className=\"p-4 rounded-lg bg-muted/50 w-fit mx-auto\">\n                                    <GitBranch className=\"h-12 w-12 text-muted-foreground\" />\n                                  </div>\n                                  <div>\n                                    <h3 className=\"text-lg font-medium mb-2\">\n                                      No Change Details\n                                    </h3>\n                                    <p className=\"text-sm text-muted-foreground\">\n                                      Change tracking was not available for this\n                                      version\n                                    </p>\n                                  </div>\n                                </div>\n                              </div>\n                            )}\n                          </div>\n                        </TabsContent>\n\n                        <TabsContent\n                          value=\"json\"\n                          className=\"flex-1 overflow-hidden p-0\"\n                        >\n                          <ScrollArea className=\"h-full\">\n                            <div className=\"p-6\">\n                              <Card className=\"overflow-hidden rounded-lg shadow-sm border\">\n                                <CardContent className=\"p-6\">\n                                  <div className=\"flex items-center gap-3 mb-4\">\n                                    <div className=\"p-2 rounded-md bg-primary/10\">\n                                      <ArrowRight className=\"h-5 w-5 text-primary\" />\n                                    </div>\n                                    <h4 className=\"font-semibold text-lg\">\n                                      Rule JSON Structure\n                                    </h4>\n                                  </div>\n                                  <div className=\"bg-background rounded-md border overflow-hidden\">\n                                    <JsonViewer\n                                      data={selectedEntry.rule}\n                                      rootName=\"rule\"\n                                      defaultExpanded={true}\n                                      className=\"max-w-full\"\n                                      highlightLogicalOperators={true}\n                                    />\n                                  </div>\n                                </CardContent>\n                              </Card>\n                            </div>\n                          </ScrollArea>\n                        </TabsContent>\n\n                        {compareEntry && (\n                          <TabsContent\n                            value=\"compare\"\n                            className=\"flex-1 overflow-hidden p-0\"\n                          >\n                            <div className=\"h-full p-6\">\n                              <div className=\"h-full bg-card rounded-lg border overflow-hidden\">\n                                <div className=\"p-4 bg-muted/30 border-b\">\n                                  <div className=\"flex items-center gap-3\">\n                                    <div className=\"p-2 rounded-md bg-primary/10\">\n                                      <ArrowLeft className=\"h-5 w-5 text-primary\" />\n                                    </div>\n                                    <div>\n                                      <h4 className=\"font-semibold text-lg\">\n                                        Version Comparison\n                                      </h4>\n                                      <p className=\"text-sm text-muted-foreground\">\n                                        Comparing v\n                                        {history.indexOf(compareEntry) + 1} → v\n                                        {history.indexOf(selectedEntry) + 1}\n                                      </p>\n                                    </div>\n                                  </div>\n                                </div>\n                                <DiffViewer\n                                  oldValue={compareEntry.rule}\n                                  newValue={selectedEntry.rule}\n                                  oldTitle={`Version ${history.indexOf(compareEntry) + 1}`}\n                                  newTitle={`Version ${history.indexOf(selectedEntry) + 1}`}\n                                  title={`Comparing v${history.indexOf(compareEntry) + 1} → v${history.indexOf(selectedEntry) + 1}`}\n                                  className=\"flex-1\"\n                                />\n                              </div>\n                            </div>\n                          </TabsContent>\n                        )}\n                      </Tabs>\n                    ) : (\n                      <div className=\"h-full flex items-center justify-center p-8\">\n                        <div className=\"text-center space-y-4\">\n                          <div className=\"p-6 rounded-lg bg-muted/50 w-fit mx-auto\">\n                            <Eye className=\"h-16 w-16 text-muted-foreground\" />\n                          </div>\n                          <div>\n                            <h3 className=\"text-xl font-medium mb-2\">\n                              Select a Version\n                            </h3>\n                            <p className=\"text-sm text-muted-foreground max-w-sm\">\n                              Choose a history entry from the list to view its\n                              details, changes, and JSON structure\n                            </p>\n                          </div>\n                        </div>\n                      </div>\n                    )}\n                  </CardContent>\n                </Card>\n              </ResizablePanel>\n            </div>\n          </div>\n        </ZoomDialogContent>\n      </ZoomDialog>\n    </>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/inputs/AnimatedNumberInput.tsx",
    "content": "import React, { useState, useRef } from \"react\";\nimport NumberFlow, { useCanAnimate } from \"@number-flow/react\";\nimport { Input } from \"../ui/input\";\nimport { cn } from \"../../lib/utils\";\nimport { ChevronUp, ChevronDown } from \"lucide-react\";\n\n// Extract default props to prevent infinite re-renders\nconst defaultFormat: Intl.NumberFormatOptions = {};\n\ninterface AnimatedNumberInputProps {\n  value?: number | string;\n  onChange: (value: string) => void;\n  placeholder?: string;\n  disabled?: boolean;\n  className?: string;\n  min?: number;\n  max?: number;\n  step?: number;\n  format?: Intl.NumberFormatOptions;\n}\n\nexport const AnimatedNumberInput: React.FC<AnimatedNumberInputProps> = ({\n  value,\n  onChange,\n  placeholder = \"Enter a number\",\n  disabled = false,\n  className,\n  min,\n  max,\n  step = 1,\n  format = defaultFormat,\n}) => {\n  const [isEditing, setIsEditing] = useState(false);\n  const [editValue, setEditValue] = useState(\"\");\n  const inputRef = useRef<HTMLInputElement>(null);\n  const canAnimate = useCanAnimate();\n\n  const numericValue =\n    typeof value === \"string\" ? Number.parseFloat(value) || 0 : value || 0;\n\n  const handleStartEdit = () => {\n    setIsEditing(true);\n    setEditValue(numericValue.toString());\n    setTimeout(() => inputRef.current?.select(), 0);\n  };\n\n  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const newValue = e.target.value;\n\n    // Allow empty value, negative sign, and decimal point\n    if (newValue === \"\" || newValue === \"-\" || newValue === \".\") {\n      setEditValue(newValue);\n      return;\n    }\n\n    // Validate number format\n    const numberRegex = /^-?\\d*(?:\\.\\d*)?$/;\n    if (!numberRegex.test(newValue)) {\n      return;\n    }\n\n    setEditValue(newValue);\n  };\n\n  const handleBlur = () => {\n    const numValue = Number.parseFloat(editValue);\n\n    if (!Number.isNaN(numValue)) {\n      let finalValue = numValue;\n\n      // Apply constraints\n      if (min !== undefined && finalValue < min) finalValue = min;\n      if (max !== undefined && finalValue > max) finalValue = max;\n\n      onChange(finalValue.toString());\n    }\n\n    setIsEditing(false);\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n    if (e.key === \"Enter\") {\n      handleBlur();\n    } else if (e.key === \"Escape\") {\n      setIsEditing(false);\n    }\n  };\n\n  const adjustValue = (delta: number) => {\n    const newValue = numericValue + delta;\n\n    // Check constraints\n    if (min !== undefined && newValue < min) return;\n    if (max !== undefined && newValue > max) return;\n\n    onChange(newValue.toString());\n  };\n\n  if (isEditing) {\n    return (\n      <Input\n        ref={inputRef}\n        type=\"text\"\n        inputMode=\"decimal\"\n        value={editValue}\n        onChange={handleChange}\n        onBlur={handleBlur}\n        onKeyDown={handleKeyDown}\n        placeholder={placeholder}\n        disabled={disabled}\n        className={cn(\"font-mono\", className)}\n        autoFocus\n      />\n    );\n  }\n\n  return (\n    <div className={cn(\"relative group\", className)}>\n      <div\n        onClick={handleStartEdit}\n        className={cn(\n          \"flex items-center justify-between px-3 py-2 text-sm rounded-md border border-input bg-background cursor-text transition-colors\",\n          \"hover:bg-accent hover:text-accent-foreground\",\n          disabled && \"opacity-50 cursor-not-allowed pointer-events-none\",\n        )}\n      >\n        <div className=\"font-mono\">\n          {canAnimate ? (\n            <NumberFlow\n              value={numericValue}\n              format={{\n                ...format,\n                notation:\n                  format.notation === \"scientific\" ||\n                  format.notation === \"engineering\"\n                    ? \"standard\"\n                    : format.notation,\n              }}\n              animated\n            />\n          ) : (\n            new Intl.NumberFormat(undefined, format).format(numericValue)\n          )}\n        </div>\n\n        <div className=\"flex flex-col -space-y-1 ml-2 opacity-0 group-hover:opacity-100 transition-opacity\">\n          <button\n            type=\"button\"\n            onClick={(e) => {\n              e.stopPropagation();\n              adjustValue(step);\n            }}\n            disabled={disabled || (max !== undefined && numericValue >= max)}\n            className=\"p-0.5 hover:bg-muted rounded disabled:opacity-50\"\n          >\n            <ChevronUp className=\"h-3 w-3\" />\n          </button>\n          <button\n            type=\"button\"\n            onClick={(e) => {\n              e.stopPropagation();\n              adjustValue(-step);\n            }}\n            disabled={disabled || (min !== undefined && numericValue <= min)}\n            className=\"p-0.5 hover:bg-muted rounded disabled:opacity-50\"\n          >\n            <ChevronDown className=\"h-3 w-3\" />\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/inputs/ArrayInput.tsx",
    "content": "import React from \"react\";\nimport { Button } from \"../ui/button\";\nimport { Input } from \"../ui/input\";\nimport { Badge } from \"../ui/badge\";\nimport { X, Plus } from \"lucide-react\";\nimport { cn } from \"../../lib/utils\";\n\n// Extract default props to prevent infinite re-renders\nconst defaultValue: any[] = [];\n\ninterface ArrayInputProps {\n  value?: any[];\n  onChange: (value: any[]) => void;\n  itemType?: \"string\" | \"number\" | \"boolean\";\n  placeholder?: string;\n  disabled?: boolean;\n  className?: string;\n}\n\nexport const ArrayInput: React.FC<ArrayInputProps> = ({\n  value = defaultValue,\n  onChange,\n  itemType = \"string\",\n  placeholder = \"Add item\",\n  disabled = false,\n  className,\n}) => {\n  const [inputValue, setInputValue] = React.useState(\"\");\n\n  const handleAdd = () => {\n    if (!inputValue.trim()) return;\n\n    let newValue: any = inputValue;\n    if (itemType === \"number\") {\n      newValue = Number.parseFloat(inputValue);\n      if (Number.isNaN(newValue)) return;\n    } else if (itemType === \"boolean\") {\n      newValue = inputValue.toLowerCase() === \"true\";\n    }\n\n    onChange([...value, newValue]);\n    setInputValue(\"\");\n  };\n\n  const handleRemove = (index: number) => {\n    onChange(value.filter((_, i) => i !== index));\n  };\n\n  const handleKeyPress = (e: React.KeyboardEvent) => {\n    if (e.key === \"Enter\") {\n      e.preventDefault();\n      handleAdd();\n    }\n  };\n\n  return (\n    <div className={cn(\"space-y-2\", className)}>\n      <div className=\"flex gap-2\">\n        <Input\n          value={inputValue}\n          onChange={(e) => setInputValue(e.target.value)}\n          onKeyPress={handleKeyPress}\n          placeholder={placeholder}\n          disabled={disabled}\n          className=\"flex-1\"\n          type={itemType === \"number\" ? \"number\" : \"text\"}\n        />\n        <Button\n          type=\"button\"\n          onClick={handleAdd}\n          disabled={disabled || !inputValue.trim()}\n          size=\"icon\"\n        >\n          <Plus className=\"h-4 w-4\" />\n        </Button>\n      </div>\n      {value.length > 0 && (\n        <div className=\"flex flex-wrap gap-1\">\n          {value.map((item, index) => (\n            <Badge\n              key={index}\n              variant=\"secondary\"\n              className=\"pl-2 pr-1 py-1 flex items-center gap-1\"\n            >\n              <span className=\"text-xs font-normal\">\n                {typeof item === \"string\" ? item : JSON.stringify(item)}\n              </span>\n              <button\n                type=\"button\"\n                onClick={() => handleRemove(index)}\n                disabled={disabled}\n                className=\"ml-1 hover:text-destructive\"\n              >\n                <X className=\"h-3 w-3\" />\n              </button>\n            </Badge>\n          ))}\n        </div>\n      )}\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/inputs/BooleanInput.tsx",
    "content": "import React from \"react\";\nimport { Switch } from \"../ui/switch\";\nimport { Label } from \"../ui/label\";\nimport { cn } from \"../../lib/utils\";\n\ninterface BooleanInputProps {\n  value?: boolean;\n  onChange: (value: boolean) => void;\n  label?: string;\n  disabled?: boolean;\n  className?: string;\n}\n\nexport const BooleanInput: React.FC<BooleanInputProps> = ({\n  value = false,\n  onChange,\n  label,\n  disabled = false,\n  className,\n}) => {\n  return (\n    <div className={cn(\"flex items-center space-x-2\", className)}>\n      <Switch checked={value} onCheckedChange={onChange} disabled={disabled} />\n      {label && <Label className=\"text-sm font-normal\">{label}</Label>}\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/inputs/DateInput.tsx",
    "content": "import React from \"react\";\nimport { format } from \"date-fns\";\nimport { Calendar as CalendarIcon } from \"lucide-react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../ui/button\";\nimport { Calendar } from \"../ui/calendar\";\nimport { PopoverTrigger, PopoverContent, Popover } from \"../ui/popover\";\n\ninterface DateInputProps {\n  value?: string | Date;\n  onChange: (value: string) => void;\n  placeholder?: string;\n  disabled?: boolean;\n  className?: string;\n}\n\nexport const DateInput: React.FC<DateInputProps> = ({\n  value,\n  onChange,\n  placeholder = \"Pick a date\",\n  disabled = false,\n  className,\n}) => {\n  const date = React.useMemo(() => {\n    if (!value) return undefined;\n\n    try {\n      const parsed = new Date(value);\n      // Check if date is valid\n      if (Number.isNaN(parsed.getTime())) {\n        return undefined;\n      }\n      return parsed;\n    } catch {\n      return undefined;\n    }\n  }, [value]);\n\n  return (\n    <Popover>\n      <PopoverTrigger asChild>\n        <Button\n          variant=\"outline\"\n          className={cn(\n            \"justify-start text-left font-normal\",\n            !date && \"text-muted-foreground\",\n            className,\n          )}\n          disabled={disabled}\n        >\n          <CalendarIcon className=\"mr-2 h-4 w-4\" />\n          {date ? format(date, \"PPP\") : <span>{placeholder}</span>}\n        </Button>\n      </PopoverTrigger>\n      <PopoverContent className=\"w-auto p-0\" align=\"start\">\n        <Calendar\n          mode=\"single\"\n          selected={date}\n          onSelect={(newDate) => {\n            if (newDate) {\n              onChange(newDate.toISOString());\n            }\n          }}\n          initialFocus\n          disabled={(date) =>\n            date > new Date() || date < new Date(\"1900-01-01\")\n          }\n        />\n      </PopoverContent>\n    </Popover>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/inputs/NumberInput.tsx",
    "content": "import React from \"react\";\nimport { Input } from \"../ui/input\";\nimport { Slider } from \"../ui/slider\";\nimport { cn } from \"../../lib/utils\";\n\ninterface NumberInputProps {\n  value?: number;\n  onChange: (value: number) => void;\n  min?: number;\n  max?: number;\n  step?: number;\n  showSlider?: boolean;\n  placeholder?: string;\n  disabled?: boolean;\n  className?: string;\n}\n\nexport const NumberInput: React.FC<NumberInputProps> = ({\n  value,\n  onChange,\n  min,\n  max,\n  step = 1,\n  showSlider = false,\n  placeholder = \"Enter number\",\n  disabled = false,\n  className,\n}) => {\n  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const newValue =\n      e.target.value === \"\" ? 0 : Number.parseFloat(e.target.value);\n    if (!Number.isNaN(newValue)) {\n      onChange(newValue);\n    }\n  };\n\n  const handleSliderChange = (values: number[]) => {\n    onChange(values[0]);\n  };\n\n  return (\n    <div className={cn(\"space-y-2\", className)}>\n      <Input\n        type=\"number\"\n        value={value ?? \"\"}\n        onChange={handleInputChange}\n        min={min}\n        max={max}\n        step={step}\n        placeholder={placeholder}\n        disabled={disabled}\n        className=\"font-mono\"\n      />\n      {showSlider && min !== undefined && max !== undefined && (\n        <div className=\"px-2\">\n          <Slider\n            value={[value ?? min]}\n            onValueChange={handleSliderChange}\n            min={min}\n            max={max}\n            step={step}\n            disabled={disabled}\n          />\n          <div className=\"flex justify-between text-xs text-muted-foreground mt-1\">\n            <span>{min}</span>\n            <span>{max}</span>\n          </div>\n        </div>\n      )}\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/inputs/SmartValueInput.tsx",
    "content": "import React from \"react\";\nimport { Input } from \"../ui/input\";\nimport { DateInput } from \"./DateInput\";\nimport { AnimatedNumberInput } from \"./AnimatedNumberInput\";\nimport { BooleanInput } from \"./BooleanInput\";\nimport { ArrayInput } from \"./ArrayInput\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectItem,\n  SelectContent,\n  Select,\n} from \"../ui/select\";\nimport { Badge } from \"../ui/badge\";\nimport { Info } from \"lucide-react\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"../ui/tooltip\";\nimport { getOperatorConfig } from \"../../utils/operators\";\nimport type { OperatorsType } from \"@usex/rule-engine\";\nimport type { FieldConfig } from \"../../types\";\nimport { cn } from \"../../lib/utils\";\n\ninterface SmartValueInputProps {\n  value: any;\n  onChange: (value: any) => void;\n  operator: OperatorsType;\n  field?: FieldConfig;\n  sampleData?: Record<string, any>;\n  disabled?: boolean;\n  className?: string;\n}\n\nexport const SmartValueInput: React.FC<SmartValueInputProps> = ({\n  value,\n  onChange,\n  operator,\n  field,\n  sampleData: _sampleData,\n  disabled = false,\n  className,\n}) => {\n  const operatorConfig = getOperatorConfig(operator);\n  const valueType = operatorConfig?.valueType || \"single\";\n\n  // No input needed for these operators\n  if (valueType === \"none\") {\n    return (\n      <div\n        className={cn(\n          \"flex items-center gap-2 text-sm text-muted-foreground\",\n          className,\n        )}\n      >\n        <Info className=\"h-4 w-4\" />\n        <span>No value needed</span>\n      </div>\n    );\n  }\n\n  // For predefined values\n  if (field?.values && field.values.length > 0) {\n    if (valueType === \"multiple\") {\n      return (\n        <div className={cn(\"space-y-2\", className)}>\n          <Select\n            value=\"\"\n            onValueChange={(newValue) => {\n              const currentArray = Array.isArray(value) ? value : [];\n              if (!currentArray.includes(newValue)) {\n                onChange([...currentArray, newValue]);\n              }\n            }}\n            disabled={disabled}\n          >\n            <SelectTrigger>\n              <SelectValue placeholder=\"Select values...\" />\n            </SelectTrigger>\n            <SelectContent>\n              {field.values.map((option) => (\n                <SelectItem key={option.value} value={option.value}>\n                  {option.label}\n                </SelectItem>\n              ))}\n            </SelectContent>\n          </Select>\n          {Array.isArray(value) && value.length > 0 && (\n            <div className=\"flex flex-wrap gap-1\">\n              {value.map((v, index) => (\n                <Badge key={index} variant=\"secondary\">\n                  {field.values?.find((opt) => opt.value === v)?.label || v}\n                  <button\n                    type=\"button\"\n                    onClick={() =>\n                      onChange(value.filter((_, i) => i !== index))\n                    }\n                    className=\"ml-1\"\n                  >\n                    ×\n                  </button>\n                </Badge>\n              ))}\n            </div>\n          )}\n        </div>\n      );\n    }\n\n    return (\n      <Select value={value} onValueChange={onChange} disabled={disabled}>\n        <SelectTrigger className={className}>\n          <SelectValue placeholder=\"Select value...\" />\n        </SelectTrigger>\n        <SelectContent>\n          {field.values.map((option) => (\n            <SelectItem key={option.value} value={option.value}>\n              {option.label}\n            </SelectItem>\n          ))}\n        </SelectContent>\n      </Select>\n    );\n  }\n\n  // For range values (between operators)\n  if (valueType === \"range\") {\n    const rangeValue = Array.isArray(value) ? value : [value || \"\", \"\"];\n\n    if (field?.type === \"date\" || operator.includes(\"date\")) {\n      return (\n        <div className={cn(\"space-y-2\", className)}>\n          <div>\n            <label className=\"text-xs text-muted-foreground\">From</label>\n            <DateInput\n              value={rangeValue[0]}\n              onChange={(newValue) => onChange([newValue, rangeValue[1]])}\n              disabled={disabled}\n            />\n          </div>\n          <div>\n            <label className=\"text-xs text-muted-foreground\">To</label>\n            <DateInput\n              value={rangeValue[1]}\n              onChange={(newValue) => onChange([rangeValue[0], newValue])}\n              disabled={disabled}\n            />\n          </div>\n        </div>\n      );\n    }\n\n    return (\n      <div className={cn(\"space-y-2\", className)}>\n        <div>\n          <label className=\"text-xs text-muted-foreground\">From</label>\n          <AnimatedNumberInput\n            value={rangeValue[0]}\n            onChange={(newValue) => onChange([newValue, rangeValue[1]])}\n            disabled={disabled}\n            format={{\n              minimumFractionDigits: 0,\n              maximumFractionDigits: 2,\n            }}\n          />\n        </div>\n        <div>\n          <label className=\"text-xs text-muted-foreground\">To</label>\n          <AnimatedNumberInput\n            value={rangeValue[1]}\n            onChange={(newValue) => onChange([rangeValue[0], newValue])}\n            disabled={disabled}\n            format={{\n              minimumFractionDigits: 0,\n              maximumFractionDigits: 2,\n            }}\n          />\n        </div>\n      </div>\n    );\n  }\n\n  // For multiple values (in/not-in operators)\n  if (valueType === \"multiple\") {\n    return (\n      <ArrayInput\n        value={value}\n        onChange={onChange}\n        itemType={field?.type as any}\n        disabled={disabled}\n        className={className}\n      />\n    );\n  }\n\n  // Single value inputs based on field type\n  if (field?.type === \"date\" || operator.includes(\"date\")) {\n    return (\n      <DateInput\n        value={value}\n        onChange={onChange}\n        disabled={disabled}\n        className={className}\n      />\n    );\n  }\n\n  if (\n    field?.type === \"number\" ||\n    operator.includes(\"length\") ||\n    [\"min\", \"max\"].includes(operator)\n  ) {\n    return (\n      <AnimatedNumberInput\n        value={value}\n        onChange={onChange}\n        disabled={disabled}\n        className={className}\n        format={{\n          minimumFractionDigits: 0,\n          maximumFractionDigits: 2,\n        }}\n      />\n    );\n  }\n\n  if (field?.type === \"boolean\") {\n    return (\n      <BooleanInput\n        value={value}\n        onChange={onChange}\n        disabled={disabled}\n        className={className}\n      />\n    );\n  }\n\n  // Check if value is a field reference\n  const isFieldReference = typeof value === \"string\" && value.startsWith(\"$.\");\n\n  return (\n    <div className={cn(\"relative\", className)}>\n      <Input\n        value={value || \"\"}\n        onChange={(e) => onChange(e.target.value)}\n        placeholder={\n          operator === \"matches\" ? \"Enter regex pattern\" : \"Enter value\"\n        }\n        disabled={disabled}\n        className={cn(isFieldReference && \"pr-20 font-mono text-xs\")}\n      />\n      {isFieldReference && (\n        <TooltipProvider>\n          <Tooltip>\n            <TooltipTrigger asChild>\n              <Badge\n                variant=\"outline\"\n                className=\"absolute right-2 top-1/2 -translate-y-1/2 text-xs\"\n              >\n                Field Ref\n              </Badge>\n            </TooltipTrigger>\n            <TooltipContent>\n              <p>This value references another field</p>\n            </TooltipContent>\n          </Tooltip>\n        </TooltipProvider>\n      )}\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/operators/ArrayOperatorHandler.tsx",
    "content": "import React from \"react\";\nimport { Input } from \"../ui/input\";\nimport { Button } from \"../ui/button\";\nimport { Label } from \"../ui/label\";\nimport { Badge } from \"../ui/badge\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectItem,\n  SelectContent,\n  Select,\n} from \"../ui/select\";\nimport { X, Plus, Info } from \"lucide-react\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"../ui/tooltip\";\nimport { AlertDescription, Alert } from \"../ui/alert\";\nimport type { OperatorHandlerProps } from \"./index\";\n\nexport const ArrayOperatorHandler: React.FC<OperatorHandlerProps> = ({\n  operator,\n  value,\n  onChange,\n  field,\n  fieldType,\n  disabled,\n}) => {\n  const items = Array.isArray(value) ? value : value ? [value] : [];\n\n  const addItem = () => {\n    onChange([...items, \"\"]);\n  };\n\n  const updateItem = (index: number, newValue: any) => {\n    const newItems = [...items];\n    newItems[index] = newValue;\n    onChange(newItems);\n  };\n\n  const removeItem = (index: number) => {\n    onChange(items.filter((_, i) => i !== index));\n  };\n\n  const parseValue = (val: string, type?: string) => {\n    if (type === \"number\" || fieldType === \"number\") {\n      const num = Number.parseFloat(val);\n      return Number.isNaN(num) ? val : num;\n    }\n    if (type === \"boolean\" || fieldType === \"boolean\") {\n      return val === \"true\";\n    }\n    return val;\n  };\n\n  const getOperatorDescription = () => {\n    const descriptions = {\n      in: \"Value must be one of the items in the list\",\n      \"not-in\": \"Value must NOT be in the list\",\n      contains: \"Array field contains the specified value\",\n      \"not-contains\": \"Array field does NOT contain the specified value\",\n      \"contains-any\": \"Array field contains ANY of the specified values\",\n      \"contains-all\": \"Array field contains ALL of the specified values\",\n      \"not-contains-any\":\n        \"Array field does NOT contain ANY of the specified values\",\n      \"not-contains-all\":\n        \"Array field does NOT contain ALL of the specified values\",\n    };\n    return descriptions[operator as keyof typeof descriptions] || operator;\n  };\n\n  const isArrayFieldOperator = [\n    \"contains\",\n    \"not-contains\",\n    \"contains-any\",\n    \"contains-all\",\n    \"not-contains-any\",\n    \"not-contains-all\",\n  ].includes(operator);\n\n  return (\n    <div className=\"space-y-4\">\n      <div>\n        <div className=\"flex items-center gap-2 mb-2\">\n          <Label>\n            {isArrayFieldOperator ? \"Values to Check\" : \"Allowed Values\"}\n          </Label>\n          <Badge variant=\"outline\" className=\"text-xs\">\n            {items.length} item{items.length !== 1 ? \"s\" : \"\"}\n          </Badge>\n          <TooltipProvider>\n            <Tooltip>\n              <TooltipTrigger>\n                <Info className=\"h-3 w-3 text-muted-foreground\" />\n              </TooltipTrigger>\n              <TooltipContent className=\"max-w-xs\">\n                <p className=\"font-semibold mb-1\">\n                  {operator.toUpperCase()} Operator\n                </p>\n                <p className=\"text-xs\">{getOperatorDescription()}</p>\n              </TooltipContent>\n            </Tooltip>\n          </TooltipProvider>\n        </div>\n\n        <Alert className=\"mb-3\">\n          <Info className=\"h-4 w-4\" />\n          <AlertDescription className=\"text-xs\">\n            {isArrayFieldOperator ? (\n              <span>\n                Checking if <strong>{field}</strong> (array){\" \"}\n                {getOperatorDescription().toLowerCase()}\n              </span>\n            ) : (\n              <span>\n                Checking if <strong>{field}</strong>{\" \"}\n                {getOperatorDescription().toLowerCase()}\n              </span>\n            )}\n          </AlertDescription>\n        </Alert>\n      </div>\n\n      <div className=\"space-y-2\">\n        {items.map((item, index) => (\n          <div key={index} className=\"flex items-center gap-2\">\n            <div className=\"flex-1\">\n              {fieldType === \"boolean\" ? (\n                <Select\n                  value={item?.toString() || \"\"}\n                  onValueChange={(val) => updateItem(index, val === \"true\")}\n                  disabled={disabled}\n                >\n                  <SelectTrigger>\n                    <SelectValue placeholder=\"Select boolean value\" />\n                  </SelectTrigger>\n                  <SelectContent>\n                    <SelectItem value=\"true\">True</SelectItem>\n                    <SelectItem value=\"false\">False</SelectItem>\n                  </SelectContent>\n                </Select>\n              ) : (\n                <Input\n                  type={fieldType === \"number\" ? \"number\" : \"text\"}\n                  value={item || \"\"}\n                  onChange={(e) =>\n                    updateItem(index, parseValue(e.target.value, fieldType))\n                  }\n                  placeholder={`Enter ${fieldType || \"value\"}`}\n                  disabled={disabled}\n                  className=\"font-mono\"\n                />\n              )}\n            </div>\n            <Button\n              variant=\"ghost\"\n              size=\"icon\"\n              onClick={() => removeItem(index)}\n              disabled={disabled}\n            >\n              <X className=\"h-4 w-4\" />\n            </Button>\n          </div>\n        ))}\n\n        <Button\n          variant=\"outline\"\n          size=\"sm\"\n          onClick={addItem}\n          disabled={disabled}\n          className=\"w-full\"\n        >\n          <Plus className=\"h-4 w-4 mr-2\" />\n          Add Item\n        </Button>\n      </div>\n\n      {items.length > 0 && (\n        <div className=\"p-3 bg-muted rounded-md\">\n          <p className=\"text-xs text-muted-foreground mb-2\">Preview:</p>\n          <code className=\"text-xs font-mono\">\n            {field} {operator} [\n            {items\n              .map((i) => (typeof i === \"string\" ? `\"${i}\"` : i))\n              .join(\", \")}\n            ]\n          </code>\n        </div>\n      )}\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/operators/BooleanValidationHandler.tsx",
    "content": "import React from \"react\";\nimport { Label } from \"../ui/label\";\nimport { Badge } from \"../ui/badge\";\nimport { Switch } from \"../ui/switch\";\nimport { ToggleRight, ToggleLeft, Info, Hash, Binary } from \"lucide-react\";\nimport { AlertTitle, AlertDescription, Alert } from \"../ui/alert\";\nimport { CardContent, Card } from \"../ui/card\";\nimport { Separator } from \"../ui/separator\";\nimport type { OperatorHandlerProps } from \"./index\";\n\nexport const BooleanValidationHandler: React.FC<OperatorHandlerProps> = ({\n  operator,\n  value,\n  onChange,\n  field,\n}) => {\n  // Boolean validators don't need a value\n  React.useEffect(() => {\n    if (value !== undefined) {\n      onChange(undefined);\n    }\n  }, [value, onChange]);\n\n  const getValidationInfo = () => {\n    const info = {\n      truthy: {\n        title: \"Truthy Value\",\n        description: \"Value evaluates to true in a boolean context\",\n        icon: ToggleRight,\n        color: \"text-green-600 dark:text-green-400\",\n        truthyExamples: [\"true\", \"1\", '\"text\"', \"[]\", \"{}\", \"new Date()\"],\n        falsyExamples: [\"false\", \"0\", '\"\"', \"null\", \"undefined\", \"NaN\"],\n      },\n      falsy: {\n        title: \"Falsy Value\",\n        description: \"Value evaluates to false in a boolean context\",\n        icon: ToggleLeft,\n        color: \"text-red-600 dark:text-red-400\",\n        truthyExamples: [\"false\", \"0\", '\"\"', \"null\", \"undefined\", \"NaN\"],\n        falsyExamples: [\"true\", \"1\", '\"text\"', \"[]\", \"{}\", \"new Date()\"],\n      },\n      \"boolean-string\": {\n        title: \"Boolean String\",\n        description: 'String representation of a boolean (\"true\" or \"false\")',\n        icon: Binary,\n        color: \"text-blue-600 dark:text-blue-400\",\n        truthyExamples: ['\"true\"', '\"TRUE\"', '\"True\"'],\n        falsyExamples: [\n          '\"false\"',\n          '\"FALSE\"',\n          '\"False\"',\n          '\"yes\"',\n          '\"1\"',\n          \"true (actual boolean)\",\n        ],\n      },\n      \"boolean-number\": {\n        title: \"Boolean Number\",\n        description: \"Numeric representation of a boolean (1 or 0)\",\n        icon: Hash,\n        color: \"text-purple-600 dark:text-purple-400\",\n        truthyExamples: [\"1\", \"0\"],\n        falsyExamples: [\"2\", \"-1\", \"0.5\", \"true\", '\"1\"'],\n      },\n    };\n    return (\n      info[operator as keyof typeof info] || {\n        title: operator,\n        description: \"Custom boolean validation\",\n        icon: Info,\n        color: \"text-gray-600\",\n        truthyExamples: [],\n        falsyExamples: [],\n      }\n    );\n  };\n\n  const validationInfo = getValidationInfo();\n  const Icon = validationInfo.icon;\n\n  // Interactive demo for truthy/falsy\n  const [demoValue, setDemoValue] = React.useState(\"\");\n  const getDemoResult = () => {\n    if (!demoValue) return null;\n    try {\n      // eslint-disable-next-line no-eval\n      const evaluated = eval(demoValue);\n      if (operator === \"truthy\") return !!evaluated;\n      if (operator === \"falsy\") return !evaluated;\n      if (operator === \"boolean-string\") {\n        return (\n          typeof evaluated === \"string\" &&\n          [\"true\", \"false\"].includes(evaluated.toLowerCase())\n        );\n      }\n      if (operator === \"boolean-number\") {\n        return evaluated === 0 || evaluated === 1;\n      }\n    } catch {\n      return false;\n    }\n  };\n\n  return (\n    <div className=\"space-y-4\">\n      <div>\n        <div className=\"flex items-center gap-2 mb-3\">\n          <Label>Boolean Validation</Label>\n          <Badge variant=\"outline\" className=\"text-xs\">\n            No config needed\n          </Badge>\n        </div>\n\n        <Card>\n          <CardContent className=\"pt-6\">\n            <div className=\"flex items-start gap-3\">\n              <Icon className={`h-5 w-5 mt-0.5 ${validationInfo.color}`} />\n              <div className=\"flex-1 space-y-3\">\n                <div>\n                  <h4 className=\"font-medium\">{validationInfo.title}</h4>\n                  <p className=\"text-sm text-muted-foreground mt-1\">\n                    {validationInfo.description}\n                  </p>\n                </div>\n\n                <Separator />\n\n                <div className=\"grid grid-cols-2 gap-4\">\n                  <div>\n                    <p className=\"text-xs font-medium text-green-600 dark:text-green-400 mb-2\">\n                      ✓ Valid Examples\n                    </p>\n                    <div className=\"space-y-1\">\n                      {validationInfo.truthyExamples.map((example, index) => (\n                        <code\n                          key={index}\n                          className=\"block text-xs bg-green-50 dark:bg-green-950 text-green-700 dark:text-green-300 px-2 py-1 rounded\"\n                        >\n                          {example}\n                        </code>\n                      ))}\n                    </div>\n                  </div>\n                  <div>\n                    <p className=\"text-xs font-medium text-red-600 dark:text-red-400 mb-2\">\n                      ✗ Invalid Examples\n                    </p>\n                    <div className=\"space-y-1\">\n                      {validationInfo.falsyExamples.map((example, index) => (\n                        <code\n                          key={index}\n                          className=\"block text-xs bg-red-50 dark:bg-red-950 text-red-700 dark:text-red-300 px-2 py-1 rounded\"\n                        >\n                          {example}\n                        </code>\n                      ))}\n                    </div>\n                  </div>\n                </div>\n\n                {(operator === \"truthy\" || operator === \"falsy\") && (\n                  <>\n                    <Separator />\n                    <div>\n                      <p className=\"text-xs font-medium text-muted-foreground mb-2\">\n                        Interactive Demo\n                      </p>\n                      <div className=\"flex items-center gap-2\">\n                        <input\n                          type=\"text\"\n                          value={demoValue}\n                          onChange={(e) => setDemoValue(e.target.value)}\n                          placeholder=\"Try: true, 1, '', null, []\"\n                          className=\"flex-1 text-xs px-2 py-1 rounded border bg-background\"\n                        />\n                        {demoValue && (\n                          <Badge\n                            variant={getDemoResult() ? \"default\" : \"secondary\"}\n                          >\n                            {getDemoResult() ? \"✓ Passes\" : \"✗ Fails\"}\n                          </Badge>\n                        )}\n                      </div>\n                    </div>\n                  </>\n                )}\n              </div>\n            </div>\n          </CardContent>\n        </Card>\n      </div>\n\n      <Alert>\n        <Icon className=\"h-4 w-4\" />\n        <AlertTitle className=\"text-sm\">Validating Field</AlertTitle>\n        <AlertDescription className=\"text-xs\">\n          <strong>{field}</strong> must be a{\" \"}\n          {validationInfo.title.toLowerCase()}\n        </AlertDescription>\n      </Alert>\n\n      <div className=\"p-3 bg-muted rounded-md\">\n        <p className=\"text-xs text-muted-foreground mb-2\">Rule Preview:</p>\n        <code className=\"text-xs font-mono\">\n          {field} {operator}\n        </code>\n      </div>\n\n      {/* Visual representation for different operators */}\n      {operator === \"truthy\" && (\n        <div className=\"flex items-center justify-center p-4 bg-green-50 dark:bg-green-950 rounded-lg\">\n          <Switch\n            checked={true}\n            disabled\n            className=\"data-[state=checked]:bg-green-600\"\n          />\n          <span className=\"ml-3 text-sm font-medium text-green-700 dark:text-green-300\">\n            Value must be truthy\n          </span>\n        </div>\n      )}\n\n      {operator === \"falsy\" && (\n        <div className=\"flex items-center justify-center p-4 bg-red-50 dark:bg-red-950 rounded-lg\">\n          <Switch checked={false} disabled />\n          <span className=\"ml-3 text-sm font-medium text-red-700 dark:text-red-300\">\n            Value must be falsy\n          </span>\n        </div>\n      )}\n\n      {operator === \"boolean-string\" && (\n        <div className=\"flex items-center justify-center gap-4 p-4 bg-blue-50 dark:bg-blue-950 rounded-lg\">\n          <code className=\"text-sm font-mono text-blue-700 dark:text-blue-300\">\n            \"true\"\n          </code>\n          <span className=\"text-blue-500\">or</span>\n          <code className=\"text-sm font-mono text-blue-700 dark:text-blue-300\">\n            \"false\"\n          </code>\n        </div>\n      )}\n\n      {operator === \"boolean-number\" && (\n        <div className=\"flex items-center justify-center gap-4 p-4 bg-purple-50 dark:bg-purple-950 rounded-lg\">\n          <code className=\"text-sm font-mono text-purple-700 dark:text-purple-300\">\n            1\n          </code>\n          <span className=\"text-purple-500\">or</span>\n          <code className=\"text-sm font-mono text-purple-700 dark:text-purple-300\">\n            0\n          </code>\n        </div>\n      )}\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/operators/ComparisonOperatorHandler.tsx",
    "content": "import type { OperatorHandlerProps } from \"./index\";\nimport { Sparkles, Info, Hash } from \"lucide-react\";\nimport React from \"react\";\nimport { DynamicFieldSelector } from \"../DynamicFieldSelector\";\nimport { AlertDescription, Alert } from \"../ui/alert\";\nimport { Badge } from \"../ui/badge\";\nimport { Button } from \"../ui/button\";\nimport { Input } from \"../ui/input\";\nimport { Label } from \"../ui/label\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectItem,\n  SelectContent,\n  Select,\n} from \"../ui/select\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"../ui/tooltip\";\n\nexport const ComparisonOperatorHandler: React.FC<OperatorHandlerProps> = ({\n  operator,\n  value,\n  onChange,\n  field,\n  fieldType,\n  sampleData,\n  disabled,\n}) => {\n  const [inputMode, setInputMode] = React.useState<\"value\" | \"field\">(\n    typeof value === \"string\" && value.startsWith(\"$.\") ? \"field\" : \"value\",\n  );\n  const isLikeOperator = operator === \"like\" || operator === \"not-like\";\n  const isNumericOperator = [\n    \"greater-than\",\n    \"less-than\",\n    \"greater-than-or-equals\",\n    \"less-than-or-equals\",\n  ].includes(operator);\n\n  // Common header with mode toggle\n  const renderHeader = () => (\n    <div className=\"flex items-center justify-between mb-2\">\n      <div className=\"flex items-center gap-2\">\n        <Label>Value</Label>\n        {fieldType && (\n          <Badge variant=\"outline\" className=\"text-xs\">\n            {fieldType}\n          </Badge>\n        )}\n      </div>\n      <div className=\"flex items-center gap-1\">\n        <Button\n          variant={inputMode === \"value\" ? \"secondary\" : \"ghost\"}\n          size=\"sm\"\n          className=\"h-7 px-2\"\n          onClick={() => setInputMode(\"value\")}\n          disabled={disabled}\n        >\n          <Hash className=\"h-3 w-3 mr-1\" />\n          Static\n        </Button>\n        <Button\n          variant={inputMode === \"field\" ? \"secondary\" : \"ghost\"}\n          size=\"sm\"\n          className=\"h-7 px-2\"\n          onClick={() => setInputMode(\"field\")}\n          disabled={disabled}\n        >\n          <Sparkles className=\"h-3 w-3 mr-1\" />\n          Dynamic\n        </Button>\n      </div>\n    </div>\n  );\n\n  // For numeric comparisons\n  if (isNumericOperator) {\n    return (\n      <div className=\"space-y-3\">\n        {renderHeader()}\n        {inputMode === \"field\" ? (\n          <>\n            <DynamicFieldSelector\n              value={value}\n              onChange={onChange}\n              sampleData={sampleData}\n              placeholder=\"Select field to compare\"\n              disabled={disabled}\n            />\n            <Alert>\n              <Info className=\"h-4 w-4\" />\n              <AlertDescription className=\"text-xs\">\n                Compare {field} with the value from another field\n              </AlertDescription>\n            </Alert>\n          </>\n        ) : (\n          <>\n            <Input\n              type=\"number\"\n              value={value || \"\"}\n              onChange={(e) =>\n                onChange(\n                  e.target.value\n                    ? Number.parseFloat(e.target.value)\n                    : undefined,\n                )\n              }\n              placeholder=\"Enter number\"\n              disabled={disabled}\n              className=\"font-mono\"\n            />\n            <div className=\"flex gap-2\">\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                onClick={() => onChange(0)}\n                disabled={disabled}\n              >\n                Zero\n              </Button>\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                onClick={() => onChange(100)}\n                disabled={disabled}\n              >\n                100\n              </Button>\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                onClick={() => onChange(1000)}\n                disabled={disabled}\n              >\n                1K\n              </Button>\n            </div>\n          </>\n        )}\n      </div>\n    );\n  }\n\n  // For like/not-like operators (pattern matching)\n  if (isLikeOperator) {\n    return (\n      <div className=\"space-y-3\">\n        <div className=\"flex items-center gap-2\">\n          <Label>Pattern</Label>\n          <Badge variant=\"outline\" className=\"text-xs\">\n            SQL LIKE\n          </Badge>\n          <TooltipProvider>\n            <Tooltip>\n              <TooltipTrigger>\n                <Info className=\"h-3 w-3 text-muted-foreground\" />\n              </TooltipTrigger>\n              <TooltipContent className=\"max-w-xs\">\n                <p className=\"font-semibold mb-1\">Pattern matching:</p>\n                <ul className=\"text-xs space-y-1\">\n                  <li>• % - matches any sequence of characters</li>\n                  <li>• _ - matches any single character</li>\n                  <li>\n                    • Example: \"%john%\" matches \"john\", \"johnny\", \"big john\"\n                  </li>\n                </ul>\n              </TooltipContent>\n            </Tooltip>\n          </TooltipProvider>\n        </div>\n        <Input\n          value={value || \"\"}\n          onChange={(e) => onChange(e.target.value)}\n          placeholder=\"Enter pattern (e.g., %value%)\"\n          disabled={disabled}\n          className=\"font-mono\"\n        />\n        <div className=\"space-y-2\">\n          <Label className=\"text-xs text-muted-foreground\">\n            Quick patterns:\n          </Label>\n          <div className=\"flex flex-wrap gap-2\">\n            <Button\n              variant=\"outline\"\n              size=\"sm\"\n              onClick={() => {\n                const currentValue = value?.toString().replace(/%/g, \"\") || \"\";\n                onChange(`%${currentValue}%`);\n              }}\n              disabled={disabled}\n            >\n              Contains\n            </Button>\n            <Button\n              variant=\"outline\"\n              size=\"sm\"\n              onClick={() => {\n                const currentValue = value?.toString().replace(/%/g, \"\") || \"\";\n                onChange(`${currentValue}%`);\n              }}\n              disabled={disabled}\n            >\n              Starts with\n            </Button>\n            <Button\n              variant=\"outline\"\n              size=\"sm\"\n              onClick={() => {\n                const currentValue = value?.toString().replace(/%/g, \"\") || \"\";\n                onChange(`%${currentValue}`);\n              }}\n              disabled={disabled}\n            >\n              Ends with\n            </Button>\n            <Button\n              variant=\"outline\"\n              size=\"sm\"\n              onClick={() => onChange(`%__%`)}\n              disabled={disabled}\n            >\n              At least 2 chars\n            </Button>\n          </div>\n        </div>\n        {value && (\n          <Alert>\n            <Info className=\"h-4 w-4\" />\n            <AlertDescription className=\"text-xs\">\n              Pattern preview:{\" \"}\n              <code className=\"font-mono bg-muted px-1\">{value}</code>\n            </AlertDescription>\n          </Alert>\n        )}\n      </div>\n    );\n  }\n\n  // Default comparison (equals/not-equals)\n  return (\n    <div className=\"space-y-3\">\n      {renderHeader()}\n      {inputMode === \"field\" ? (\n        <>\n          <DynamicFieldSelector\n            value={value}\n            onChange={onChange}\n            sampleData={sampleData}\n            placeholder=\"Select field to compare\"\n            disabled={disabled}\n          />\n          <Alert>\n            <Info className=\"h-4 w-4\" />\n            <AlertDescription className=\"text-xs\">\n              Compare {field} with the value from another field dynamically\n            </AlertDescription>\n          </Alert>\n        </>\n      ) : (\n        <>\n          {/* Conditional inputs based on field type */}\n          {fieldType === \"boolean\" ? (\n            <Select\n              value={value?.toString()}\n              onValueChange={(v) => onChange(v === \"true\")}\n              disabled={disabled}\n            >\n              <SelectTrigger>\n                <SelectValue placeholder=\"Select boolean value\" />\n              </SelectTrigger>\n              <SelectContent>\n                <SelectItem value=\"true\">True</SelectItem>\n                <SelectItem value=\"false\">False</SelectItem>\n              </SelectContent>\n            </Select>\n          ) : fieldType === \"number\" ? (\n            <Input\n              type=\"number\"\n              value={value || \"\"}\n              onChange={(e) =>\n                onChange(\n                  e.target.value\n                    ? Number.parseFloat(e.target.value)\n                    : undefined,\n                )\n              }\n              placeholder=\"Enter number\"\n              disabled={disabled}\n              className=\"font-mono\"\n            />\n          ) : (\n            <Input\n              value={value || \"\"}\n              onChange={(e) => onChange(e.target.value)}\n              placeholder=\"Enter value to compare\"\n              disabled={disabled}\n            />\n          )}\n\n          {/* Quick values based on field type */}\n          {fieldType === \"string\" && (\n            <div className=\"flex gap-2\">\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                onClick={() => onChange(\"\")}\n                disabled={disabled}\n              >\n                Empty\n              </Button>\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                onClick={() => onChange(\"null\")}\n                disabled={disabled}\n              >\n                \"null\"\n              </Button>\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                onClick={() => onChange(\"undefined\")}\n                disabled={disabled}\n              >\n                \"undefined\"\n              </Button>\n            </div>\n          )}\n        </>\n      )}\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/operators/DateOperatorHandler.tsx",
    "content": "import React from \"react\";\nimport { Input } from \"../ui/input\";\nimport { Button } from \"../ui/button\";\nimport { Label } from \"../ui/label\";\nimport { Badge } from \"../ui/badge\";\nimport {\n  SelectValue,\n  SelectTrigger,\n  SelectItem,\n  SelectContent,\n  Select,\n} from \"../ui/select\";\nimport { Info, Clock, Calendar } from \"lucide-react\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"../ui/tooltip\";\nimport { AlertDescription, Alert } from \"../ui/alert\";\nimport { PopoverTrigger, PopoverContent, Popover } from \"../ui/popover\";\nimport { Calendar as CalendarComponent } from \"../ui/calendar\";\nimport { format } from \"date-fns\";\nimport type { OperatorHandlerProps } from \"./index\";\n\n// Date picker component\nconst DatePicker: React.FC<{\n  value: string;\n  onChange: (value: string) => void;\n  disabled?: boolean;\n  placeholder?: string;\n}> = ({ value, onChange, disabled, placeholder }) => {\n  const [isOpen, setIsOpen] = React.useState(false);\n  const date = value ? new Date(value) : undefined;\n\n  return (\n    <div className=\"flex gap-2\">\n      <Input\n        value={value || \"\"}\n        onChange={(e) => onChange(e.target.value)}\n        placeholder={placeholder || \"YYYY-MM-DD\"}\n        disabled={disabled}\n        className=\"font-mono\"\n      />\n      <Popover open={isOpen} onOpenChange={setIsOpen}>\n        <PopoverTrigger asChild>\n          <Button variant=\"outline\" size=\"icon\" disabled={disabled}>\n            <Calendar className=\"h-4 w-4\" />\n          </Button>\n        </PopoverTrigger>\n        <PopoverContent className=\"w-auto p-0\" align=\"start\">\n          <CalendarComponent\n            mode=\"single\"\n            selected={date}\n            onSelect={(newDate) => {\n              if (newDate) {\n                onChange(format(newDate, \"yyyy-MM-dd\"));\n                setIsOpen(false);\n              }\n            }}\n            initialFocus\n          />\n        </PopoverContent>\n      </Popover>\n    </div>\n  );\n};\n\nexport const DateOperatorHandler: React.FC<OperatorHandlerProps> = ({\n  operator,\n  value,\n  onChange,\n  field,\n  disabled,\n}) => {\n  const isRelativeOperator = [\"date-after-now\", \"date-before-now\"].includes(\n    operator,\n  );\n  const isBetweenOperator = [\"date-between\", \"date-not-between\"].includes(\n    operator,\n  );\n\n  const getOperatorDescription = () => {\n    const descriptions = {\n      \"date-after\": \"Date must be after the specified date\",\n      \"date-before\": \"Date must be before the specified date\",\n      \"date-equals\": \"Date must be exactly the specified date\",\n      \"date-between\": \"Date must be between two dates (inclusive)\",\n      \"date-not-between\": \"Date must NOT be between two dates\",\n      \"date-after-now\": \"Date must be after the current date/time plus offset\",\n      \"date-before-now\":\n        \"Date must be before the current date/time minus offset\",\n      \"date-after-or-equals\":\n        \"Date must be after or equal to the specified date\",\n      \"date-before-or-equals\":\n        \"Date must be before or equal to the specified date\",\n    };\n    return descriptions[operator as keyof typeof descriptions] || operator;\n  };\n\n  // Handle relative date operators (date-after-now, date-before-now)\n  if (isRelativeOperator) {\n    const relativeValue =\n      typeof value === \"object\" && value !== null\n        ? value\n        : { value: 0, unit: \"days\" };\n\n    return (\n      <div className=\"space-y-4\">\n        <div>\n          <div className=\"flex items-center gap-2 mb-2\">\n            <Label>Time Offset</Label>\n            <Badge variant=\"outline\" className=\"text-xs\">\n              Relative to now\n            </Badge>\n            <TooltipProvider>\n              <Tooltip>\n                <TooltipTrigger>\n                  <Info className=\"h-3 w-3 text-muted-foreground\" />\n                </TooltipTrigger>\n                <TooltipContent className=\"max-w-xs\">\n                  <p className=\"font-semibold mb-1\">Relative Date Check</p>\n                  <p className=\"text-xs\">{getOperatorDescription()}</p>\n                </TooltipContent>\n              </Tooltip>\n            </TooltipProvider>\n          </div>\n        </div>\n\n        <div className=\"flex gap-2\">\n          <Input\n            type=\"number\"\n            value={relativeValue.value || 0}\n            onChange={(e) =>\n              onChange({\n                ...relativeValue,\n                value: Number.parseInt(e.target.value) || 0,\n              })\n            }\n            placeholder=\"0\"\n            disabled={disabled}\n            className=\"w-24\"\n          />\n          <Select\n            value={relativeValue.unit || \"days\"}\n            onValueChange={(unit) => onChange({ ...relativeValue, unit })}\n            disabled={disabled}\n          >\n            <SelectTrigger className=\"w-32\">\n              <SelectValue />\n            </SelectTrigger>\n            <SelectContent>\n              <SelectItem value=\"minutes\">Minutes</SelectItem>\n              <SelectItem value=\"hours\">Hours</SelectItem>\n              <SelectItem value=\"days\">Days</SelectItem>\n              <SelectItem value=\"weeks\">Weeks</SelectItem>\n              <SelectItem value=\"months\">Months</SelectItem>\n              <SelectItem value=\"years\">Years</SelectItem>\n            </SelectContent>\n          </Select>\n        </div>\n\n        <Alert>\n          <Clock className=\"h-4 w-4\" />\n          <AlertDescription className=\"text-xs\">\n            {operator === \"date-after-now\" ? (\n              <span>\n                Checking if <strong>{field}</strong> is after: now +{\" \"}\n                {relativeValue.value} {relativeValue.unit}\n              </span>\n            ) : (\n              <span>\n                Checking if <strong>{field}</strong> is before: now -{\" \"}\n                {relativeValue.value} {relativeValue.unit}\n              </span>\n            )}\n          </AlertDescription>\n        </Alert>\n      </div>\n    );\n  }\n\n  // Handle between operators\n  if (isBetweenOperator) {\n    const betweenValue =\n      Array.isArray(value) && value.length === 2 ? value : [\"\", \"\"];\n\n    return (\n      <div className=\"space-y-4\">\n        <div>\n          <div className=\"flex items-center gap-2 mb-2\">\n            <Label>Date Range</Label>\n            <Badge variant=\"outline\" className=\"text-xs\">\n              Inclusive\n            </Badge>\n            <TooltipProvider>\n              <Tooltip>\n                <TooltipTrigger>\n                  <Info className=\"h-3 w-3 text-muted-foreground\" />\n                </TooltipTrigger>\n                <TooltipContent>\n                  <p>{getOperatorDescription()}</p>\n                </TooltipContent>\n              </Tooltip>\n            </TooltipProvider>\n          </div>\n        </div>\n\n        <div className=\"space-y-3\">\n          <div>\n            <Label className=\"text-xs text-muted-foreground mb-1\">\n              Start Date\n            </Label>\n            <DatePicker\n              value={betweenValue[0]}\n              onChange={(date) => onChange([date, betweenValue[1]])}\n              disabled={disabled}\n              placeholder=\"Select start date\"\n            />\n          </div>\n          <div>\n            <Label className=\"text-xs text-muted-foreground mb-1\">\n              End Date\n            </Label>\n            <DatePicker\n              value={betweenValue[1]}\n              onChange={(date) => onChange([betweenValue[0], date])}\n              disabled={disabled}\n              placeholder=\"Select end date\"\n            />\n          </div>\n        </div>\n\n        {betweenValue[0] && betweenValue[1] && (\n          <Alert>\n            <Calendar className=\"h-4 w-4\" />\n            <AlertDescription className=\"text-xs\">\n              <span>\n                Checking if <strong>{field}</strong> is{\" \"}\n                {operator === \"date-between\" ? \"between\" : \"NOT between\"}{\" \"}\n                {betweenValue[0]} and {betweenValue[1]}\n              </span>\n            </AlertDescription>\n          </Alert>\n        )}\n      </div>\n    );\n  }\n\n  // Handle single date operators\n  return (\n    <div className=\"space-y-4\">\n      <div>\n        <div className=\"flex items-center gap-2 mb-2\">\n          <Label>Date Value</Label>\n          <TooltipProvider>\n            <Tooltip>\n              <TooltipTrigger>\n                <Info className=\"h-3 w-3 text-muted-foreground\" />\n              </TooltipTrigger>\n              <TooltipContent>\n                <p>{getOperatorDescription()}</p>\n              </TooltipContent>\n            </Tooltip>\n          </TooltipProvider>\n        </div>\n      </div>\n\n      <DatePicker\n        value={value}\n        onChange={onChange}\n        disabled={disabled}\n        placeholder=\"Select date\"\n      />\n\n      {value && (\n        <Alert>\n          <Calendar className=\"h-4 w-4\" />\n          <AlertDescription className=\"text-xs\">\n            <span>\n              Checking if <strong>{field}</strong> is{\" \"}\n              {operator.replace(\"date-\", \"\").replace(/-/g, \" \")} {value}\n            </span>\n          </AlertDescription>\n        </Alert>\n      )}\n\n      <div className=\"flex gap-2\">\n        <Button\n          variant=\"outline\"\n          size=\"sm\"\n          onClick={() => onChange(new Date().toISOString().split(\"T\")[0])}\n          disabled={disabled}\n        >\n          Today\n        </Button>\n        <Button\n          variant=\"outline\"\n          size=\"sm\"\n          onClick={() => {\n            const tomorrow = new Date();\n            tomorrow.setDate(tomorrow.getDate() + 1);\n            onChange(tomorrow.toISOString().split(\"T\")[0]);\n          }}\n          disabled={disabled}\n        >\n          Tomorrow\n        </Button>\n        <Button\n          variant=\"outline\"\n          size=\"sm\"\n          onClick={() => {\n            const yesterday = new Date();\n            yesterday.setDate(yesterday.getDate() - 1);\n            onChange(yesterday.toISOString().split(\"T\")[0]);\n          }}\n          disabled={disabled}\n        >\n          Yesterday\n        </Button>\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/operators/ExistenceOperatorHandler.tsx",
    "content": "import React from \"react\";\nimport { Label } from \"../ui/label\";\nimport { Badge } from \"../ui/badge\";\nimport { XCircle, Info, CheckCircle2, AlertCircle } from \"lucide-react\";\nimport { AlertTitle, AlertDescription, Alert } from \"../ui/alert\";\nimport { CardContent, Card } from \"../ui/card\";\nimport type { OperatorHandlerProps } from \"./index\";\n\nexport const ExistenceOperatorHandler: React.FC<OperatorHandlerProps> = ({\n  operator,\n  value,\n  onChange,\n  field,\n}) => {\n  // Existence operators don't need a value, so we ensure it's always undefined\n  React.useEffect(() => {\n    if (value !== undefined) {\n      onChange(undefined);\n    }\n  }, [value, onChange]);\n\n  const getOperatorInfo = () => {\n    const info = {\n      exists: {\n        title: \"Field Exists\",\n        description: \"Checks if the field is present in the data\",\n        icon: CheckCircle2,\n        color: \"text-green-600 dark:text-green-400\",\n        examples: ['{ name: \"John\" } ✓', \"{ age: 25 } ✗\"],\n      },\n      \"not-exists\": {\n        title: \"Field Does Not Exist\",\n        description: \"Checks if the field is NOT present in the data\",\n        icon: XCircle,\n        color: \"text-red-600 dark:text-red-400\",\n        examples: ['{ name: \"John\" } ✗', \"{ age: 25 } ✓\"],\n      },\n      \"null-or-undefined\": {\n        title: \"Null or Undefined\",\n        description: \"Checks if the field value is null or undefined\",\n        icon: AlertCircle,\n        color: \"text-yellow-600 dark:text-yellow-400\",\n        examples: [\"null ✓\", \"undefined ✓\", '\"\" ✗', \"0 ✗\", \"false ✗\"],\n      },\n      \"not-null-or-undefined\": {\n        title: \"Not Null or Undefined\",\n        description: \"Checks if the field value is NOT null or undefined\",\n        icon: CheckCircle2,\n        color: \"text-blue-600 dark:text-blue-400\",\n        examples: [\"null ✗\", \"undefined ✗\", '\"\" ✓', \"0 ✓\", \"false ✓\"],\n      },\n      empty: {\n        title: \"Empty\",\n        description:\n          'Checks if the field value is empty (null, undefined, \"\", [], {})',\n        icon: AlertCircle,\n        color: \"text-orange-600 dark:text-orange-400\",\n        examples: [\"null ✓\", \"[] ✓\", \"{} ✓\", '\"\" ✓', '\" \" ✗', \"[1] ✗\"],\n      },\n      \"not-empty\": {\n        title: \"Not Empty\",\n        description: \"Checks if the field value is NOT empty\",\n        icon: CheckCircle2,\n        color: \"text-green-600 dark:text-green-400\",\n        examples: [\"null ✗\", \"[] ✗\", \"{} ✗\", '\"\" ✗', '\" \" ✓', \"[1] ✓\"],\n      },\n      \"null-or-whitespace\": {\n        title: \"Null or Whitespace\",\n        description:\n          \"Checks if the field is null, undefined, or contains only whitespace\",\n        icon: AlertCircle,\n        color: \"text-gray-600 dark:text-gray-400\",\n        examples: [\"null ✓\", '\" \" ✓', '\"  \\\\t\\\\n  \" ✓', '\"text\" ✗'],\n      },\n      \"not-null-or-whitespace\": {\n        title: \"Not Null or Whitespace\",\n        description:\n          \"Checks if the field has actual content (not just whitespace)\",\n        icon: CheckCircle2,\n        color: \"text-green-600 dark:text-green-400\",\n        examples: [\"null ✗\", '\" \" ✗', '\"  \\\\t\\\\n  \" ✗', '\"text\" ✓'],\n      },\n    };\n    return (\n      info[operator as keyof typeof info] || {\n        title: operator,\n        description: \"Custom existence check\",\n        icon: Info,\n        color: \"text-gray-600\",\n        examples: [],\n      }\n    );\n  };\n\n  const operatorInfo = getOperatorInfo();\n  const Icon = operatorInfo.icon;\n\n  return (\n    <div className=\"space-y-4\">\n      <div>\n        <div className=\"flex items-center gap-2 mb-3\">\n          <Label>Existence Check</Label>\n          <Badge variant=\"outline\" className=\"text-xs\">\n            No value required\n          </Badge>\n        </div>\n\n        <Card>\n          <CardContent className=\"pt-6\">\n            <div className=\"flex items-start gap-3\">\n              <Icon className={`h-5 w-5 mt-0.5 ${operatorInfo.color}`} />\n              <div className=\"flex-1 space-y-2\">\n                <h4 className=\"font-medium\">{operatorInfo.title}</h4>\n                <p className=\"text-sm text-muted-foreground\">\n                  {operatorInfo.description}\n                </p>\n\n                {operatorInfo.examples.length > 0 && (\n                  <div className=\"mt-3 space-y-1\">\n                    <p className=\"text-xs font-medium text-muted-foreground\">\n                      Examples:\n                    </p>\n                    <div className=\"flex flex-wrap gap-2\">\n                      {operatorInfo.examples.map((example, index) => (\n                        <code\n                          key={index}\n                          className=\"text-xs bg-muted px-2 py-1 rounded\"\n                        >\n                          {example}\n                        </code>\n                      ))}\n                    </div>\n                  </div>\n                )}\n              </div>\n            </div>\n          </CardContent>\n        </Card>\n      </div>\n\n      <Alert>\n        <Info className=\"h-4 w-4\" />\n        <AlertTitle className=\"text-sm\">Checking Field</AlertTitle>\n        <AlertDescription className=\"text-xs\">\n          <strong>{field}</strong> will be checked for{\" \"}\n          {operatorInfo.title.toLowerCase()}\n        </AlertDescription>\n      </Alert>\n\n      <div className=\"p-3 bg-muted rounded-md\">\n        <p className=\"text-xs text-muted-foreground mb-2\">Rule Preview:</p>\n        <code className=\"text-xs font-mono\">\n          {field} {operator}\n        </code>\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/operators/LengthValidationHandler.tsx",
    "content": "import React from \"react\";\nimport { Input } from \"../ui/input\";\nimport { Label } from \"../ui/label\";\nimport { Badge } from \"../ui/badge\";\nimport { Slider } from \"../ui/slider\";\nimport {\n  Ruler,\n  MoveHorizontal,\n  Minimize2,\n  Maximize2,\n  Info,\n} from \"lucide-react\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"../ui/tooltip\";\nimport { AlertTitle, AlertDescription, Alert } from \"../ui/alert\";\nimport { CardContent, Card } from \"../ui/card\";\nimport type { OperatorHandlerProps } from \"./index\";\n\nexport const LengthValidationHandler: React.FC<OperatorHandlerProps> = ({\n  operator,\n  value,\n  onChange,\n  field,\n  fieldType,\n  disabled,\n}) => {\n  const isBetweenOperator = [\"length-between\", \"not-length-between\"].includes(\n    operator,\n  );\n\n  const getValidationInfo = () => {\n    const info = {\n      \"string-length\": {\n        title: \"Has Length Property\",\n        description:\n          \"Validates that the value is a string or array with a length property\",\n        icon: Ruler,\n        color: \"text-gray-600 dark:text-gray-400\",\n        examples: [\n          '\"hello\" ✓ (length: 5)',\n          \"[] ✓ (length: 0)\",\n          \"123 ✗\",\n          \"null ✗\",\n        ],\n        needsInput: false,\n        target: \"string or array\",\n      },\n      \"min-length\": {\n        title: \"Minimum Length\",\n        description:\n          \"Length must be greater than or equal to the specified value\",\n        icon: Maximize2,\n        color: \"text-green-600 dark:text-green-400\",\n        examples: [\n          'Min: 5 → \"hello\" ✓',\n          'Min: 5 → \"hi\" ✗',\n          \"Min: 2 → [1,2,3] ✓\",\n        ],\n        needsInput: true,\n        target: \"string or array\",\n      },\n      \"max-length\": {\n        title: \"Maximum Length\",\n        description: \"Length must be less than or equal to the specified value\",\n        icon: Minimize2,\n        color: \"text-red-600 dark:text-red-400\",\n        examples: [\n          'Max: 10 → \"hello\" ✓',\n          'Max: 3 → \"hello\" ✗',\n          \"Max: 5 → [1,2,3] ✓\",\n        ],\n        needsInput: true,\n        target: \"string or array\",\n      },\n      \"length-between\": {\n        title: \"Length Between Range\",\n        description: \"Length must be within the specified range (inclusive)\",\n        icon: MoveHorizontal,\n        color: \"text-blue-600 dark:text-blue-400\",\n        examples: [\n          'Range: 3-10 → \"hello\" ✓',\n          'Range: 3-10 → \"hi\" ✗',\n          \"Range: 2-5 → [1,2,3] ✓\",\n        ],\n        needsInput: true,\n        target: \"string or array\",\n      },\n      \"not-length-between\": {\n        title: \"Length Outside Range\",\n        description: \"Length must NOT be within the specified range\",\n        icon: MoveHorizontal,\n        color: \"text-purple-600 dark:text-purple-400\",\n        examples: [\n          'Range: 3-10 → \"hi\" ✓',\n          'Range: 3-10 → \"hello\" ✗',\n          \"Range: 2-5 → [1] ✓\",\n        ],\n        needsInput: true,\n        target: \"string or array\",\n      },\n    };\n    return (\n      info[operator as keyof typeof info] || {\n        title: operator,\n        description: \"Custom length validation\",\n        icon: Info,\n        color: \"text-gray-600\",\n        examples: [],\n        needsInput: false,\n        target: \"value\",\n      }\n    );\n  };\n\n  const validationInfo = getValidationInfo();\n  const Icon = validationInfo.icon;\n\n  // For validators that don't need input, ensure value is undefined\n  React.useEffect(() => {\n    if (!validationInfo.needsInput && value !== undefined) {\n      onChange(undefined);\n    }\n  }, [value, onChange, validationInfo.needsInput]);\n\n  // Determine if we're working with strings or arrays based on field type\n  const targetType = fieldType === \"array\" ? \"array\" : \"string\";\n  const unitLabel = targetType === \"array\" ? \"items\" : \"characters\";\n\n  // Handle between operators\n  if (isBetweenOperator) {\n    const rangeValue =\n      Array.isArray(value) && value.length === 2 ? value : [0, 50];\n\n    return (\n      <div className=\"space-y-4\">\n        <div>\n          <div className=\"flex items-center gap-2 mb-3\">\n            <Label>Length Range</Label>\n            <Badge variant=\"outline\" className=\"text-xs\">\n              {unitLabel}\n            </Badge>\n          </div>\n\n          <Card>\n            <CardContent className=\"pt-6\">\n              <div className=\"flex items-start gap-3\">\n                <Icon className={`h-5 w-5 mt-0.5 ${validationInfo.color}`} />\n                <div className=\"flex-1 space-y-2\">\n                  <h4 className=\"font-medium\">{validationInfo.title}</h4>\n                  <p className=\"text-sm text-muted-foreground\">\n                    {validationInfo.description}\n                  </p>\n\n                  {validationInfo.examples.length > 0 && (\n                    <div className=\"mt-3 space-y-1\">\n                      <p className=\"text-xs font-medium text-muted-foreground\">\n                        Examples:\n                      </p>\n                      <div className=\"space-y-1\">\n                        {validationInfo.examples.map((example, index) => (\n                          <code\n                            key={index}\n                            className=\"block text-xs bg-muted px-2 py-1 rounded\"\n                          >\n                            {example}\n                          </code>\n                        ))}\n                      </div>\n                    </div>\n                  )}\n                </div>\n              </div>\n            </CardContent>\n          </Card>\n        </div>\n\n        <div className=\"space-y-4\">\n          <div className=\"grid grid-cols-2 gap-3\">\n            <div>\n              <Label className=\"text-xs text-muted-foreground mb-1\">\n                Minimum {unitLabel}\n              </Label>\n              <Input\n                type=\"number\"\n                value={rangeValue[0]}\n                onChange={(e) =>\n                  onChange([\n                    Number.parseInt(e.target.value) || 0,\n                    rangeValue[1],\n                  ])\n                }\n                min={0}\n                disabled={disabled}\n                className=\"font-mono\"\n              />\n            </div>\n            <div>\n              <Label className=\"text-xs text-muted-foreground mb-1\">\n                Maximum {unitLabel}\n              </Label>\n              <Input\n                type=\"number\"\n                value={rangeValue[1]}\n                onChange={(e) =>\n                  onChange([\n                    rangeValue[0],\n                    Number.parseInt(e.target.value) || 0,\n                  ])\n                }\n                min={0}\n                disabled={disabled}\n                className=\"font-mono\"\n              />\n            </div>\n          </div>\n\n          <div className=\"px-3\">\n            <Slider\n              value={rangeValue}\n              onValueChange={onChange}\n              min={0}\n              max={100}\n              step={1}\n              disabled={disabled}\n              className=\"w-full\"\n            />\n            <div className=\"flex justify-between text-xs text-muted-foreground mt-1\">\n              <span>\n                {rangeValue[0]} {unitLabel}\n              </span>\n              <span>\n                {rangeValue[1]} {unitLabel}\n              </span>\n            </div>\n          </div>\n        </div>\n\n        <Alert>\n          <Icon className=\"h-4 w-4\" />\n          <AlertDescription className=\"text-xs\">\n            <strong>{field}</strong> length must{\" \"}\n            {operator === \"length-between\" ? \"be\" : \"NOT be\"} between{\" \"}\n            {rangeValue[0]} and {rangeValue[1]} {unitLabel}\n          </AlertDescription>\n        </Alert>\n      </div>\n    );\n  }\n\n  // Handle min/max length operators\n  if (operator === \"min-length\" || operator === \"max-length\") {\n    const currentValue = typeof value === \"number\" ? value : 0;\n\n    return (\n      <div className=\"space-y-4\">\n        <div>\n          <div className=\"flex items-center gap-2 mb-3\">\n            <Label>\n              {operator === \"min-length\" ? \"Minimum\" : \"Maximum\"} Length\n            </Label>\n            <Badge variant=\"outline\" className=\"text-xs\">\n              {unitLabel}\n            </Badge>\n            <TooltipProvider>\n              <Tooltip>\n                <TooltipTrigger>\n                  <Info className=\"h-3 w-3 text-muted-foreground\" />\n                </TooltipTrigger>\n                <TooltipContent>\n                  <p>{validationInfo.description}</p>\n                </TooltipContent>\n              </Tooltip>\n            </TooltipProvider>\n          </div>\n\n          <Card>\n            <CardContent className=\"pt-6\">\n              <div className=\"flex items-start gap-3\">\n                <Icon className={`h-5 w-5 mt-0.5 ${validationInfo.color}`} />\n                <div className=\"flex-1 space-y-2\">\n                  <h4 className=\"font-medium\">{validationInfo.title}</h4>\n                  <p className=\"text-sm text-muted-foreground\">\n                    {validationInfo.description}\n                  </p>\n                </div>\n              </div>\n            </CardContent>\n          </Card>\n        </div>\n\n        <div className=\"space-y-2\">\n          <Input\n            type=\"number\"\n            value={currentValue}\n            onChange={(e) => onChange(Number.parseInt(e.target.value) || 0)}\n            min={0}\n            placeholder={`Enter ${operator === \"min-length\" ? \"minimum\" : \"maximum\"} length`}\n            disabled={disabled}\n            className=\"font-mono\"\n          />\n\n          <div className=\"px-3\">\n            <Slider\n              value={[currentValue]}\n              onValueChange={([val]) => onChange(val)}\n              min={0}\n              max={100}\n              step={1}\n              disabled={disabled}\n              className=\"w-full\"\n            />\n            <div className=\"text-center text-xs text-muted-foreground mt-1\">\n              {currentValue} {unitLabel}\n            </div>\n          </div>\n        </div>\n\n        <Alert>\n          <Icon className=\"h-4 w-4\" />\n          <AlertDescription className=\"text-xs\">\n            <strong>{field}</strong> must have{\" \"}\n            {operator === \"min-length\" ? \"at least\" : \"at most\"} {currentValue}{\" \"}\n            {unitLabel}\n          </AlertDescription>\n        </Alert>\n      </div>\n    );\n  }\n\n  // Handle string-length operator (just checks for length property)\n  return (\n    <div className=\"space-y-4\">\n      <div>\n        <div className=\"flex items-center gap-2 mb-3\">\n          <Label>Length Validation</Label>\n          <Badge variant=\"outline\" className=\"text-xs\">\n            No config needed\n          </Badge>\n        </div>\n\n        <Card>\n          <CardContent className=\"pt-6\">\n            <div className=\"flex items-start gap-3\">\n              <Icon className={`h-5 w-5 mt-0.5 ${validationInfo.color}`} />\n              <div className=\"flex-1 space-y-2\">\n                <h4 className=\"font-medium\">{validationInfo.title}</h4>\n                <p className=\"text-sm text-muted-foreground\">\n                  {validationInfo.description}\n                </p>\n\n                {validationInfo.examples.length > 0 && (\n                  <div className=\"mt-3 space-y-1\">\n                    <p className=\"text-xs font-medium text-muted-foreground\">\n                      Examples:\n                    </p>\n                    <div className=\"flex flex-wrap gap-2\">\n                      {validationInfo.examples.map((example, index) => (\n                        <code\n                          key={index}\n                          className=\"text-xs bg-muted px-2 py-1 rounded\"\n                        >\n                          {example}\n                        </code>\n                      ))}\n                    </div>\n                  </div>\n                )}\n              </div>\n            </div>\n          </CardContent>\n        </Card>\n      </div>\n\n      <Alert>\n        <Ruler className=\"h-4 w-4\" />\n        <AlertTitle className=\"text-sm\">Validating Field</AlertTitle>\n        <AlertDescription className=\"text-xs\">\n          <strong>{field}</strong> must be a {validationInfo.target} with a\n          length property\n        </AlertDescription>\n      </Alert>\n\n      <div className=\"p-3 bg-muted rounded-md\">\n        <p className=\"text-xs text-muted-foreground mb-2\">Rule Preview:</p>\n        <code className=\"text-xs font-mono\">\n          {field} {operator}\n        </code>\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/operators/NumberValidationHandler.tsx",
    "content": "import React from \"react\";\nimport { Input } from \"../ui/input\";\nimport { Label } from \"../ui/label\";\nimport { Badge } from \"../ui/badge\";\nimport { Slider } from \"../ui/slider\";\nimport {\n  TrendingUp,\n  TrendingDown,\n  Plus,\n  Minus,\n  Info,\n  CircleDot,\n  ArrowUpDown,\n} from \"lucide-react\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"../ui/tooltip\";\nimport { AlertTitle, AlertDescription, Alert } from \"../ui/alert\";\nimport { CardContent, Card } from \"../ui/card\";\nimport type { OperatorHandlerProps } from \"./index\";\n\nexport const NumberValidationHandler: React.FC<OperatorHandlerProps> = ({\n  operator,\n  value,\n  onChange,\n  field,\n  disabled,\n}) => {\n  const isBetweenOperator = [\"between\", \"not-between\"].includes(operator);\n\n  const getValidationInfo = () => {\n    const info = {\n      positive: {\n        title: \"Positive Number\",\n        description: \"Number must be greater than zero\",\n        icon: Plus,\n        color: \"text-green-600 dark:text-green-400\",\n        examples: [\"1 ✓\", \"0.5 ✓\", \"0 ✗\", \"-1 ✗\"],\n        needsInput: false,\n      },\n      negative: {\n        title: \"Negative Number\",\n        description: \"Number must be less than zero\",\n        icon: Minus,\n        color: \"text-red-600 dark:text-red-400\",\n        examples: [\"-1 ✓\", \"-0.5 ✓\", \"0 ✗\", \"1 ✗\"],\n        needsInput: false,\n      },\n      zero: {\n        title: \"Zero\",\n        description: \"Number must be exactly zero\",\n        icon: CircleDot,\n        color: \"text-gray-600 dark:text-gray-400\",\n        examples: [\"0 ✓\", \"0.0 ✓\", \"0.1 ✗\", \"-0.1 ✗\"],\n        needsInput: false,\n      },\n      min: {\n        title: \"Minimum Value\",\n        description:\n          \"Number must be greater than or equal to the specified value\",\n        icon: TrendingUp,\n        color: \"text-blue-600 dark:text-blue-400\",\n        examples: [\"Min: 10 → 15 ✓\", \"Min: 10 → 10 ✓\", \"Min: 10 → 5 ✗\"],\n        needsInput: true,\n      },\n      max: {\n        title: \"Maximum Value\",\n        description: \"Number must be less than or equal to the specified value\",\n        icon: TrendingDown,\n        color: \"text-purple-600 dark:text-purple-400\",\n        examples: [\"Max: 100 → 50 ✓\", \"Max: 100 → 100 ✓\", \"Max: 100 → 150 ✗\"],\n        needsInput: true,\n      },\n      between: {\n        title: \"Between Range\",\n        description: \"Number must be within the specified range (inclusive)\",\n        icon: ArrowUpDown,\n        color: \"text-orange-600 dark:text-orange-400\",\n        examples: [\n          \"Range: 10-20 → 15 ✓\",\n          \"Range: 10-20 → 10 ✓\",\n          \"Range: 10-20 → 25 ✗\",\n        ],\n        needsInput: true,\n      },\n      \"not-between\": {\n        title: \"Outside Range\",\n        description: \"Number must NOT be within the specified range\",\n        icon: ArrowUpDown,\n        color: \"text-cyan-600 dark:text-cyan-400\",\n        examples: [\n          \"Range: 10-20 → 5 ✓\",\n          \"Range: 10-20 → 25 ✓\",\n          \"Range: 10-20 → 15 ✗\",\n        ],\n        needsInput: true,\n      },\n    };\n    return (\n      info[operator as keyof typeof info] || {\n        title: operator,\n        description: \"Custom number validation\",\n        icon: Info,\n        color: \"text-gray-600\",\n        examples: [],\n        needsInput: false,\n      }\n    );\n  };\n\n  const validationInfo = getValidationInfo();\n  const Icon = validationInfo.icon;\n\n  // For validators that don't need input, ensure value is undefined\n  React.useEffect(() => {\n    if (!validationInfo.needsInput && value !== undefined) {\n      onChange(undefined);\n    }\n  }, [value, onChange, validationInfo.needsInput]);\n\n  // Handle between operators\n  if (isBetweenOperator) {\n    const rangeValue =\n      Array.isArray(value) && value.length === 2 ? value : [0, 100];\n\n    return (\n      <div className=\"space-y-4\">\n        <div>\n          <div className=\"flex items-center gap-2 mb-3\">\n            <Label>Number Range</Label>\n            <Badge variant=\"outline\" className=\"text-xs\">\n              Inclusive\n            </Badge>\n          </div>\n\n          <Card>\n            <CardContent className=\"pt-6\">\n              <div className=\"flex items-start gap-3\">\n                <Icon className={`h-5 w-5 mt-0.5 ${validationInfo.color}`} />\n                <div className=\"flex-1 space-y-2\">\n                  <h4 className=\"font-medium\">{validationInfo.title}</h4>\n                  <p className=\"text-sm text-muted-foreground\">\n                    {validationInfo.description}\n                  </p>\n\n                  {validationInfo.examples.length > 0 && (\n                    <div className=\"mt-3 space-y-1\">\n                      <p className=\"text-xs font-medium text-muted-foreground\">\n                        Examples:\n                      </p>\n                      <div className=\"space-y-1\">\n                        {validationInfo.examples.map((example, index) => (\n                          <code\n                            key={index}\n                            className=\"block text-xs bg-muted px-2 py-1 rounded\"\n                          >\n                            {example}\n                          </code>\n                        ))}\n                      </div>\n                    </div>\n                  )}\n                </div>\n              </div>\n            </CardContent>\n          </Card>\n        </div>\n\n        <div className=\"space-y-4\">\n          <div className=\"grid grid-cols-2 gap-3\">\n            <div>\n              <Label className=\"text-xs text-muted-foreground mb-1\">\n                Minimum\n              </Label>\n              <Input\n                type=\"number\"\n                value={rangeValue[0]}\n                onChange={(e) =>\n                  onChange([\n                    Number.parseFloat(e.target.value) || 0,\n                    rangeValue[1],\n                  ])\n                }\n                disabled={disabled}\n                className=\"font-mono\"\n              />\n            </div>\n            <div>\n              <Label className=\"text-xs text-muted-foreground mb-1\">\n                Maximum\n              </Label>\n              <Input\n                type=\"number\"\n                value={rangeValue[1]}\n                onChange={(e) =>\n                  onChange([\n                    rangeValue[0],\n                    Number.parseFloat(e.target.value) || 0,\n                  ])\n                }\n                disabled={disabled}\n                className=\"font-mono\"\n              />\n            </div>\n          </div>\n\n          <div className=\"px-3\">\n            <Slider\n              value={rangeValue}\n              onValueChange={onChange}\n              min={Math.min(rangeValue[0] - 10, -100)}\n              max={Math.max(rangeValue[1] + 10, 100)}\n              step={1}\n              disabled={disabled}\n              className=\"w-full\"\n            />\n            <div className=\"flex justify-between text-xs text-muted-foreground mt-1\">\n              <span>{rangeValue[0]}</span>\n              <span>{rangeValue[1]}</span>\n            </div>\n          </div>\n        </div>\n\n        <Alert>\n          <Icon className=\"h-4 w-4\" />\n          <AlertDescription className=\"text-xs\">\n            <strong>{field}</strong> must{\" \"}\n            {operator === \"between\" ? \"be\" : \"NOT be\"} between {rangeValue[0]}{\" \"}\n            and {rangeValue[1]} (inclusive)\n          </AlertDescription>\n        </Alert>\n      </div>\n    );\n  }\n\n  // Handle min/max operators\n  if (operator === \"min\" || operator === \"max\") {\n    return (\n      <div className=\"space-y-4\">\n        <div>\n          <div className=\"flex items-center gap-2 mb-3\">\n            <Label>{operator === \"min\" ? \"Minimum\" : \"Maximum\"} Value</Label>\n            <TooltipProvider>\n              <Tooltip>\n                <TooltipTrigger>\n                  <Info className=\"h-3 w-3 text-muted-foreground\" />\n                </TooltipTrigger>\n                <TooltipContent>\n                  <p>{validationInfo.description}</p>\n                </TooltipContent>\n              </Tooltip>\n            </TooltipProvider>\n          </div>\n\n          <Card>\n            <CardContent className=\"pt-6\">\n              <div className=\"flex items-start gap-3\">\n                <Icon className={`h-5 w-5 mt-0.5 ${validationInfo.color}`} />\n                <div className=\"flex-1 space-y-2\">\n                  <h4 className=\"font-medium\">{validationInfo.title}</h4>\n                  <p className=\"text-sm text-muted-foreground\">\n                    {validationInfo.description}\n                  </p>\n                </div>\n              </div>\n            </CardContent>\n          </Card>\n        </div>\n\n        <div className=\"space-y-2\">\n          <Input\n            type=\"number\"\n            value={value || \"\"}\n            onChange={(e) =>\n              onChange(\n                e.target.value ? Number.parseFloat(e.target.value) : undefined,\n              )\n            }\n            placeholder={`Enter ${operator} value`}\n            disabled={disabled}\n            className=\"font-mono\"\n          />\n        </div>\n\n        {value !== undefined && (\n          <Alert>\n            <Icon className=\"h-4 w-4\" />\n            <AlertDescription className=\"text-xs\">\n              <strong>{field}</strong> must be {operator === \"min\" ? \"≥\" : \"≤\"}{\" \"}\n              {value}\n            </AlertDescription>\n          </Alert>\n        )}\n      </div>\n    );\n  }\n\n  // Handle simple validators (positive, negative, zero)\n  return (\n    <div className=\"space-y-4\">\n      <div>\n        <div className=\"flex items-center gap-2 mb-3\">\n          <Label>Number Validation</Label>\n          <Badge variant=\"outline\" className=\"text-xs\">\n            No config needed\n          </Badge>\n        </div>\n\n        <Card>\n          <CardContent className=\"pt-6\">\n            <div className=\"flex items-start gap-3\">\n              <Icon className={`h-5 w-5 mt-0.5 ${validationInfo.color}`} />\n              <div className=\"flex-1 space-y-2\">\n                <h4 className=\"font-medium\">{validationInfo.title}</h4>\n                <p className=\"text-sm text-muted-foreground\">\n                  {validationInfo.description}\n                </p>\n\n                {validationInfo.examples.length > 0 && (\n                  <div className=\"mt-3 space-y-1\">\n                    <p className=\"text-xs font-medium text-muted-foreground\">\n                      Examples:\n                    </p>\n                    <div className=\"flex flex-wrap gap-2\">\n                      {validationInfo.examples.map((example, index) => (\n                        <code\n                          key={index}\n                          className=\"text-xs bg-muted px-2 py-1 rounded\"\n                        >\n                          {example}\n                        </code>\n                      ))}\n                    </div>\n                  </div>\n                )}\n              </div>\n            </div>\n          </CardContent>\n        </Card>\n      </div>\n\n      <Alert>\n        <Icon className=\"h-4 w-4\" />\n        <AlertTitle className=\"text-sm\">Validating Field</AlertTitle>\n        <AlertDescription className=\"text-xs\">\n          <strong>{field}</strong> must be {validationInfo.title.toLowerCase()}\n        </AlertDescription>\n      </Alert>\n\n      <div className=\"p-3 bg-muted rounded-md\">\n        <p className=\"text-xs text-muted-foreground mb-2\">Rule Preview:</p>\n        <code className=\"text-xs font-mono\">\n          {field} {operator}\n        </code>\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/operators/SelfReferenceHandler.tsx",
    "content": "import React from \"react\";\nimport { DynamicFieldSelector } from \"../DynamicFieldSelector\";\nimport { Badge } from \"../ui/badge\";\nimport { Label } from \"../ui/label\";\nimport { Button } from \"../ui/button\";\nimport { X, Plus, Info, ArrowRight } from \"lucide-react\";\nimport { AlertDescription, Alert } from \"../ui/alert\";\nimport type { OperatorHandlerProps } from \"./index\";\n\nexport const SelfReferenceHandler: React.FC<OperatorHandlerProps> = ({\n  operator,\n  value,\n  onChange,\n  field,\n  sampleData,\n  disabled,\n}) => {\n  const fields = Array.isArray(value) ? value : value ? [value] : [];\n\n  const addField = (fieldPath: string) => {\n    if (!fields.includes(fieldPath)) {\n      onChange([...fields, fieldPath]);\n    }\n  };\n\n  const removeField = (index: number) => {\n    onChange(fields.filter((_, i) => i !== index));\n  };\n\n  const operatorDescriptions = {\n    \"self-contains-any\":\n      \"Field value contains ANY of the referenced field values\",\n    \"self-contains-all\":\n      \"Field value contains ALL of the referenced field values\",\n    \"self-contains-none\":\n      \"Field value contains NONE of the referenced field values\",\n    \"self-not-contains-any\":\n      \"Field value does NOT contain ANY of the referenced field values\",\n    \"self-not-contains-all\":\n      \"Field value does NOT contain ALL of the referenced field values\",\n  };\n\n  return (\n    <div className=\"space-y-4\">\n      <div>\n        <div className=\"flex items-center gap-2 mb-2\">\n          <Label>Referenced Fields</Label>\n          <Badge variant=\"outline\" className=\"text-xs\">\n            Self-Reference\n          </Badge>\n        </div>\n        <Alert className=\"mb-3\">\n          <Info className=\"h-4 w-4\" />\n          <AlertDescription className=\"text-xs\">\n            <strong>{field}</strong>{\" \"}\n            <ArrowRight className=\"inline h-3 w-3 mx-1\" />\n            {operatorDescriptions[\n              operator as keyof typeof operatorDescriptions\n            ] || operator}\n          </AlertDescription>\n        </Alert>\n      </div>\n\n      <div className=\"space-y-2\">\n        {fields.map((fieldPath, index) => (\n          <div key={index} className=\"flex items-center gap-2\">\n            <div className=\"flex-1\">\n              <DynamicFieldSelector\n                value={fieldPath}\n                onChange={(newValue) => {\n                  const newFields = [...fields];\n                  newFields[index] = newValue;\n                  onChange(newFields);\n                }}\n                sampleData={sampleData}\n                placeholder=\"Select field to reference\"\n                disabled={disabled}\n              />\n            </div>\n            <Button\n              variant=\"ghost\"\n              size=\"icon\"\n              onClick={() => removeField(index)}\n              disabled={disabled}\n            >\n              <X className=\"h-4 w-4\" />\n            </Button>\n          </div>\n        ))}\n\n        <Button\n          variant=\"outline\"\n          size=\"sm\"\n          onClick={() => addField(\"\")}\n          disabled={disabled}\n          className=\"w-full\"\n        >\n          <Plus className=\"h-4 w-4 mr-2\" />\n          Add Field Reference\n        </Button>\n      </div>\n\n      {fields.length > 0 && (\n        <div className=\"p-3 bg-muted rounded-md\">\n          <p className=\"text-xs text-muted-foreground mb-2\">Example:</p>\n          <code className=\"text-xs font-mono\">\n            {field} {operator} [{fields.join(\", \")}]\n          </code>\n        </div>\n      )}\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/operators/StringValidationHandler.tsx",
    "content": "import React from \"react\";\nimport { Input } from \"../ui/input\";\nimport { Button } from \"../ui/button\";\nimport { Label } from \"../ui/label\";\nimport { Badge } from \"../ui/badge\";\nimport { Textarea } from \"../ui/textarea\";\nimport { Type, Regex, Info, Hash, ArrowUpAZ, ArrowDownAZ } from \"lucide-react\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"../ui/tooltip\";\nimport { AlertTitle, AlertDescription, Alert } from \"../ui/alert\";\nimport { CardContent, Card } from \"../ui/card\";\nimport type { OperatorHandlerProps } from \"./index\";\n\n// Test regex pattern component\nconst TestRegexPattern: React.FC<{ pattern: string }> = ({ pattern }) => {\n  const [testValue, setTestValue] = React.useState(\"\");\n  const [isValid, setIsValid] = React.useState<boolean | null>(null);\n\n  React.useEffect(() => {\n    if (!testValue) {\n      setIsValid(null);\n      return;\n    }\n    try {\n      const regex = new RegExp(pattern);\n      setIsValid(regex.test(testValue));\n    } catch {\n      setIsValid(false);\n    }\n  }, [pattern, testValue]);\n\n  return (\n    <Card className=\"border-muted bg-muted/20\">\n      <CardContent className=\"p-3\">\n        <div className=\"space-y-2\">\n          <Label className=\"text-xs text-muted-foreground\">Test Input</Label>\n          <Input\n            value={testValue}\n            onChange={(e) => setTestValue(e.target.value)}\n            placeholder=\"Enter text to test against pattern\"\n            className=\"text-sm\"\n          />\n          {testValue && (\n            <div className=\"flex items-center gap-2\">\n              <Badge\n                variant={isValid ? \"default\" : \"destructive\"}\n                className=\"text-xs\"\n              >\n                {isValid ? \"Match\" : \"No Match\"}\n              </Badge>\n            </div>\n          )}\n        </div>\n      </CardContent>\n    </Card>\n  );\n};\n\nexport const StringValidationHandler: React.FC<OperatorHandlerProps> = ({\n  operator,\n  value,\n  onChange,\n  field,\n  disabled,\n}) => {\n  const needsPattern = [\"matches\", \"not-matches\"].includes(operator);\n\n  const getValidationInfo = () => {\n    const info = {\n      alpha: {\n        title: \"Alphabetic Only\",\n        description: \"String contains only alphabetic characters (a-z, A-Z)\",\n        icon: Type,\n        color: \"text-blue-600 dark:text-blue-400\",\n        examples: [\n          '\"Hello\" ✓',\n          '\"Test\" ✓',\n          '\"Hello123\" ✗',\n          '\"Hello World\" ✗ (space)',\n        ],\n        needsValue: false,\n      },\n      \"alpha-numeric\": {\n        title: \"Alphanumeric Only\",\n        description:\n          \"String contains only letters and numbers (no spaces or special chars)\",\n        icon: Hash,\n        color: \"text-green-600 dark:text-green-400\",\n        examples: [\n          '\"Hello123\" ✓',\n          '\"Test456\" ✓',\n          '\"Hello World\" ✗',\n          '\"Hello-123\" ✗',\n        ],\n        needsValue: false,\n      },\n      \"lower-case\": {\n        title: \"Lowercase Only\",\n        description: \"String contains only lowercase characters\",\n        icon: ArrowDownAZ,\n        color: \"text-purple-600 dark:text-purple-400\",\n        examples: ['\"hello\" ✓', '\"hello world\" ✓', '\"Hello\" ✗', '\"HELLO\" ✗'],\n        needsValue: false,\n      },\n      \"upper-case\": {\n        title: \"Uppercase Only\",\n        description: \"String contains only uppercase characters\",\n        icon: ArrowUpAZ,\n        color: \"text-orange-600 dark:text-orange-400\",\n        examples: ['\"HELLO\" ✓', '\"HELLO WORLD\" ✓', '\"Hello\" ✗', '\"hello\" ✗'],\n        needsValue: false,\n      },\n      matches: {\n        title: \"Matches Pattern\",\n        description: \"String matches the provided regular expression\",\n        icon: Regex,\n        color: \"text-red-600 dark:text-red-400\",\n        examples: [\n          'Pattern: ^[A-Z] → \"Hello\" ✓',\n          'Pattern: \\\\d{3}-\\\\d{3} → \"123-456\" ✓',\n        ],\n        needsValue: true,\n      },\n      \"not-matches\": {\n        title: \"Does Not Match Pattern\",\n        description: \"String does NOT match the provided regular expression\",\n        icon: Regex,\n        color: \"text-cyan-600 dark:text-cyan-400\",\n        examples: ['Pattern: ^[A-Z] → \"hello\" ✓', 'Pattern: \\\\d{3} → \"abc\" ✓'],\n        needsValue: true,\n      },\n    };\n    return (\n      info[operator as keyof typeof info] || {\n        title: operator,\n        description: \"Custom string validation\",\n        icon: Info,\n        color: \"text-gray-600\",\n        examples: [],\n        needsValue: false,\n      }\n    );\n  };\n\n  const validationInfo = getValidationInfo();\n  const Icon = validationInfo.icon;\n\n  // For non-pattern validators, we don't need a value\n  React.useEffect(() => {\n    if (!validationInfo.needsValue && value !== undefined) {\n      onChange(undefined);\n    }\n  }, [value, onChange, validationInfo.needsValue]);\n\n  const commonPatterns = [\n    { label: \"Phone (US)\", pattern: \"^\\\\(\\\\d{3}\\\\) \\\\d{3}-\\\\d{4}$\" },\n    { label: \"Postal Code (US)\", pattern: \"^\\\\d{5}(-\\\\d{4})?$\" },\n    { label: \"Hexadecimal\", pattern: \"^#?[0-9A-Fa-f]{6}$\" },\n    { label: \"Username\", pattern: \"^[a-zA-Z0-9_]{3,16}$\" },\n    {\n      label: \"Strong Password\",\n      pattern:\n        \"^(?=.*[a-z])(?=.*[A-Z])(?=.*\\\\d)(?=.*[@$!%*?&])[A-Za-z\\\\d@$!%*?&]{8,}$\",\n    },\n    {\n      label: \"IP Address\",\n      pattern:\n        \"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$\",\n    },\n  ];\n\n  return (\n    <div className=\"space-y-4\">\n      <div>\n        <div className=\"flex items-center gap-2 mb-3\">\n          <Label>String Validation</Label>\n          <Badge variant=\"outline\" className=\"text-xs\">\n            {validationInfo.needsValue\n              ? \"Pattern required\"\n              : \"No config needed\"}\n          </Badge>\n        </div>\n\n        <Card>\n          <CardContent className=\"pt-6\">\n            <div className=\"flex items-start gap-3\">\n              <Icon className={`h-5 w-5 mt-0.5 ${validationInfo.color}`} />\n              <div className=\"flex-1 space-y-2\">\n                <h4 className=\"font-medium\">{validationInfo.title}</h4>\n                <p className=\"text-sm text-muted-foreground\">\n                  {validationInfo.description}\n                </p>\n\n                {validationInfo.examples.length > 0 && (\n                  <div className=\"mt-3 space-y-1\">\n                    <p className=\"text-xs font-medium text-muted-foreground\">\n                      Examples:\n                    </p>\n                    <div className=\"space-y-1\">\n                      {validationInfo.examples.map((example, index) => (\n                        <code\n                          key={index}\n                          className=\"block text-xs bg-muted px-2 py-1 rounded\"\n                        >\n                          {example}\n                        </code>\n                      ))}\n                    </div>\n                  </div>\n                )}\n              </div>\n            </div>\n          </CardContent>\n        </Card>\n      </div>\n\n      {needsPattern && (\n        <>\n          <div className=\"space-y-2\">\n            <div className=\"flex items-center gap-2\">\n              <Label>Regular Expression Pattern</Label>\n              <TooltipProvider>\n                <Tooltip>\n                  <TooltipTrigger>\n                    <Info className=\"h-3 w-3 text-muted-foreground\" />\n                  </TooltipTrigger>\n                  <TooltipContent className=\"max-w-xs\">\n                    <p className=\"font-semibold mb-1\">RegEx Tips:</p>\n                    <ul className=\"text-xs space-y-1\">\n                      <li>• ^ - Start of string</li>\n                      <li>• $ - End of string</li>\n                      <li>• \\\\d - Any digit</li>\n                      <li>• \\\\w - Any word character</li>\n                      <li>• + - One or more</li>\n                      <li>• * - Zero or more</li>\n                      <li>• ? - Optional</li>\n                    </ul>\n                  </TooltipContent>\n                </Tooltip>\n              </TooltipProvider>\n            </div>\n            <Textarea\n              value={value || \"\"}\n              onChange={(e) => onChange(e.target.value || undefined)}\n              placeholder=\"Enter regular expression pattern\"\n              disabled={disabled}\n              className=\"font-mono min-h-[80px]\"\n            />\n          </div>\n\n          <div className=\"space-y-2\">\n            <Label className=\"text-xs text-muted-foreground\">\n              Common Patterns\n            </Label>\n            <div className=\"flex flex-wrap gap-2\">\n              {commonPatterns.map((pattern) => (\n                <Button\n                  key={pattern.label}\n                  variant=\"outline\"\n                  size=\"sm\"\n                  onClick={() => onChange(pattern.pattern)}\n                  disabled={disabled}\n                >\n                  {pattern.label}\n                </Button>\n              ))}\n            </div>\n          </div>\n\n          {value && (\n            <div className=\"space-y-2\">\n              <Label className=\"text-xs text-muted-foreground\">\n                Test Pattern\n              </Label>\n              <TestRegexPattern pattern={value} />\n            </div>\n          )}\n        </>\n      )}\n\n      <Alert>\n        <Icon className=\"h-4 w-4\" />\n        <AlertTitle className=\"text-sm\">Validating Field</AlertTitle>\n        <AlertDescription className=\"text-xs\">\n          <strong>{field}</strong> must {validationInfo.title.toLowerCase()}\n          {value && (\n            <span className=\"block mt-1 font-mono\">Pattern: {value}</span>\n          )}\n        </AlertDescription>\n      </Alert>\n\n      <div className=\"p-3 bg-muted rounded-md\">\n        <p className=\"text-xs text-muted-foreground mb-2\">Rule Preview:</p>\n        <code className=\"text-xs font-mono\">\n          {field} {operator} {value && `\"${value}\"`}\n        </code>\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/operators/TypeValidationHandler.tsx",
    "content": "import React from \"react\";\nimport { Label } from \"../ui/label\";\nimport { Badge } from \"../ui/badge\";\nimport {\n  Type,\n  ToggleLeft,\n  Link,\n  Key,\n  Info,\n  Hash,\n  CheckCircle2,\n  Calendar,\n  Box,\n  AtSign,\n} from \"lucide-react\";\nimport { AlertTitle, AlertDescription, Alert } from \"../ui/alert\";\nimport { CardContent, Card } from \"../ui/card\";\nimport { Input } from \"../ui/input\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"../ui/tooltip\";\nimport type { OperatorHandlerProps } from \"./index\";\n\nexport const TypeValidationHandler: React.FC<OperatorHandlerProps> = ({\n  operator,\n  value,\n  onChange,\n  field,\n  disabled,\n}) => {\n  const getTypeInfo = () => {\n    const info: Record<\n      string,\n      {\n        title: string;\n        description: string;\n        icon: any;\n        color: string;\n        examples: string[];\n        config: boolean;\n        configLabel?: string;\n        configPlaceholder?: string;\n      }\n    > = {\n      string: {\n        title: \"String Type\",\n        description: \"Validates that the value is a string\",\n        icon: Type,\n        color: \"text-blue-600 dark:text-blue-400\",\n        examples: ['\"hello\" ✓', \"123 ✗\", \"true ✗\", \"null ✗\"],\n        config: false,\n      },\n      number: {\n        title: \"Number Type\",\n        description: \"Validates that the value is a number\",\n        icon: Hash,\n        color: \"text-green-600 dark:text-green-400\",\n        examples: [\"123 ✓\", \"45.67 ✓\", '\"123\" ✗', \"NaN ✗\"],\n        config: false,\n      },\n      boolean: {\n        title: \"Boolean Type\",\n        description: \"Validates that the value is a boolean\",\n        icon: ToggleLeft,\n        color: \"text-purple-600 dark:text-purple-400\",\n        examples: [\"true ✓\", \"false ✓\", '\"true\" ✗', \"1 ✗\"],\n        config: false,\n      },\n      array: {\n        title: \"Array Type\",\n        description: \"Validates that the value is an array\",\n        icon: Box,\n        color: \"text-orange-600 dark:text-orange-400\",\n        examples: [\"[] ✓\", \"[1,2,3] ✓\", '[\"a\",\"b\"] ✓', \"{} ✗\", '\"array\" ✗'],\n        config: false,\n      },\n      object: {\n        title: \"Object Type\",\n        description:\n          \"Validates that the value is an object (not array or null)\",\n        icon: Box,\n        color: \"text-indigo-600 dark:text-indigo-400\",\n        examples: [\"{} ✓\", \"{a: 1} ✓\", \"[] ✗\", \"null ✗\"],\n        config: false,\n      },\n      email: {\n        title: \"Email Format\",\n        description: \"Validates that the value is a valid email address\",\n        icon: AtSign,\n        color: \"text-red-600 dark:text-red-400\",\n        examples: [\n          \"user@example.com ✓\",\n          \"test@sub.domain.com ✓\",\n          \"invalid@email ✗\",\n          \"not-an-email ✗\",\n        ],\n        config: true,\n        configLabel: \"Additional pattern (optional)\",\n        configPlaceholder: \"e.g., @company.com$\",\n      },\n      url: {\n        title: \"URL Format\",\n        description: \"Validates that the value is a valid URL\",\n        icon: Link,\n        color: \"text-cyan-600 dark:text-cyan-400\",\n        examples: [\n          \"https://example.com ✓\",\n          \"http://sub.domain.com:8080/path ✓\",\n          \"ftp://files.com ✓\",\n          \"not-a-url ✗\",\n        ],\n        config: true,\n        configLabel: \"Required protocol (optional)\",\n        configPlaceholder: \"e.g., https\",\n      },\n      uuid: {\n        title: \"UUID Format\",\n        description: \"Validates that the value is a valid UUID\",\n        icon: Key,\n        color: \"text-yellow-600 dark:text-yellow-400\",\n        examples: [\n          \"550e8400-e29b-41d4-a716-446655440000 ✓\",\n          \"12345 ✗\",\n          \"not-a-uuid ✗\",\n        ],\n        config: true,\n        configLabel: \"UUID version (optional)\",\n        configPlaceholder: \"e.g., 4\",\n      },\n      date: {\n        title: \"Date Type\",\n        description: \"Validates that the value is a valid date\",\n        icon: Calendar,\n        color: \"text-pink-600 dark:text-pink-400\",\n        examples: [\n          \"2025-01-01 ✓\",\n          \"new Date() ✓\",\n          \"2025-13-45 ✗\",\n          \"invalid-date ✗\",\n        ],\n        config: false,\n      },\n    };\n    return (\n      info[operator as keyof typeof info] || {\n        title: operator,\n        description: \"Custom type validation\",\n        icon: Info,\n        color: \"text-gray-600\",\n        examples: [],\n        config: false,\n      }\n    );\n  };\n\n  const typeInfo = getTypeInfo();\n  const Icon = typeInfo.icon;\n\n  // For most type validators, we don't need a value\n  React.useEffect(() => {\n    if (!typeInfo.config && value !== undefined) {\n      onChange(undefined);\n    }\n  }, [value, onChange, typeInfo.config]);\n\n  return (\n    <div className=\"space-y-4\">\n      <div>\n        <div className=\"flex items-center gap-2 mb-3\">\n          <Label>Type Validation</Label>\n          <Badge variant=\"outline\" className=\"text-xs\">\n            {typeInfo.config ? \"Optional config\" : \"No config needed\"}\n          </Badge>\n        </div>\n\n        <Card>\n          <CardContent className=\"pt-6\">\n            <div className=\"flex items-start gap-3\">\n              <Icon className={`h-5 w-5 mt-0.5 ${typeInfo.color}`} />\n              <div className=\"flex-1 space-y-2\">\n                <h4 className=\"font-medium\">{typeInfo.title}</h4>\n                <p className=\"text-sm text-muted-foreground\">\n                  {typeInfo.description}\n                </p>\n\n                {typeInfo.examples.length > 0 && (\n                  <div className=\"mt-3 space-y-1\">\n                    <p className=\"text-xs font-medium text-muted-foreground\">\n                      Examples:\n                    </p>\n                    <div className=\"flex flex-wrap gap-2\">\n                      {typeInfo.examples.map((example, index) => (\n                        <code\n                          key={index}\n                          className=\"text-xs bg-muted px-2 py-1 rounded\"\n                        >\n                          {example}\n                        </code>\n                      ))}\n                    </div>\n                  </div>\n                )}\n              </div>\n            </div>\n          </CardContent>\n        </Card>\n      </div>\n\n      {typeInfo.config && (\n        <div className=\"space-y-2\">\n          <div className=\"flex items-center gap-2\">\n            <Label>{typeInfo.configLabel}</Label>\n            <TooltipProvider>\n              <Tooltip>\n                <TooltipTrigger>\n                  <Info className=\"h-3 w-3 text-muted-foreground\" />\n                </TooltipTrigger>\n                <TooltipContent className=\"max-w-xs\">\n                  <p className=\"text-xs\">\n                    {operator === \"email\" &&\n                      \"Add a pattern to further restrict email format\"}\n                    {operator === \"url\" &&\n                      \"Specify required protocol (http, https, ftp, etc.)\"}\n                    {operator === \"uuid\" && \"Specify UUID version (1, 3, 4, 5)\"}\n                  </p>\n                </TooltipContent>\n              </Tooltip>\n            </TooltipProvider>\n          </div>\n          <Input\n            value={value || \"\"}\n            onChange={(e) => onChange(e.target.value || undefined)}\n            placeholder={typeInfo.configPlaceholder}\n            disabled={disabled}\n            className=\"font-mono\"\n          />\n        </div>\n      )}\n\n      <Alert>\n        <CheckCircle2 className=\"h-4 w-4\" />\n        <AlertTitle className=\"text-sm\">Validating Field</AlertTitle>\n        <AlertDescription className=\"text-xs\">\n          <strong>{field}</strong> must be a valid{\" \"}\n          {typeInfo.title.toLowerCase()}\n          {value && operator === \"email\" && (\n            <span> matching pattern: {value}</span>\n          )}\n          {value && operator === \"url\" && <span> with protocol: {value}</span>}\n          {value && operator === \"uuid\" && <span> (version {value})</span>}\n        </AlertDescription>\n      </Alert>\n\n      <div className=\"p-3 bg-muted rounded-md\">\n        <p className=\"text-xs text-muted-foreground mb-2\">Rule Preview:</p>\n        <code className=\"text-xs font-mono\">\n          {field} {operator} {value && `\"${value}\"`}\n        </code>\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/operators/index.tsx",
    "content": "import React from \"react\";\nimport { Operators } from \"@usex/rule-engine\";\nimport type { OperatorsType } from \"@usex/rule-engine\";\n\n// Import all operator handlers\nimport { ComparisonOperatorHandler } from \"./ComparisonOperatorHandler\";\nimport { ArrayOperatorHandler } from \"./ArrayOperatorHandler\";\nimport { ExistenceOperatorHandler } from \"./ExistenceOperatorHandler\";\nimport { DateOperatorHandler } from \"./DateOperatorHandler\";\nimport { TypeValidationHandler } from \"./TypeValidationHandler\";\nimport { StringValidationHandler } from \"./StringValidationHandler\";\nimport { NumberValidationHandler } from \"./NumberValidationHandler\";\nimport { LengthValidationHandler } from \"./LengthValidationHandler\";\nimport { BooleanValidationHandler } from \"./BooleanValidationHandler\";\nimport { SelfReferenceHandler } from \"./SelfReferenceHandler\";\n\nexport interface OperatorHandlerProps {\n  operator: OperatorsType;\n  value: any;\n  onChange: (value: any) => void;\n  field?: string;\n  fieldType?: string;\n  sampleData?: Record<string, any>;\n  disabled?: boolean;\n}\n\n// Map operators to their specific handlers\nconst operatorHandlers: Partial<\n  Record<OperatorsType, React.ComponentType<OperatorHandlerProps>>\n> = {\n  // Comparison operators\n  [Operators.Equals]: ComparisonOperatorHandler,\n  [Operators.NotEquals]: ComparisonOperatorHandler,\n  [Operators.Like]: ComparisonOperatorHandler,\n  [Operators.NotLike]: ComparisonOperatorHandler,\n  [Operators.GreaterThan]: ComparisonOperatorHandler,\n  [Operators.LessThan]: ComparisonOperatorHandler,\n  [Operators.GreaterThanOrEquals]: ComparisonOperatorHandler,\n  [Operators.LessThanOrEquals]: ComparisonOperatorHandler,\n\n  // Array operators\n  [Operators.In]: ArrayOperatorHandler,\n  [Operators.NotIn]: ArrayOperatorHandler,\n  [Operators.Contains]: ArrayOperatorHandler,\n  [Operators.NotContains]: ArrayOperatorHandler,\n  [Operators.ContainsAny]: ArrayOperatorHandler,\n  [Operators.ContainsAll]: ArrayOperatorHandler,\n  [Operators.NotContainsAny]: ArrayOperatorHandler,\n  [Operators.NotContainsAll]: ArrayOperatorHandler,\n\n  // Self-referencing operators\n  [Operators.SelfContainsAny]: SelfReferenceHandler,\n  [Operators.SelfContainsAll]: SelfReferenceHandler,\n  [Operators.SelfContainsNone]: SelfReferenceHandler,\n  [Operators.SelfNotContainsAny]: SelfReferenceHandler,\n  [Operators.SelfNotContainsAll]: SelfReferenceHandler,\n\n  // Existence operators\n  [Operators.Exists]: ExistenceOperatorHandler,\n  [Operators.NotExists]: ExistenceOperatorHandler,\n  [Operators.NullOrUndefined]: ExistenceOperatorHandler,\n  [Operators.NotNullOrUndefined]: ExistenceOperatorHandler,\n  [Operators.Empty]: ExistenceOperatorHandler,\n  [Operators.NotEmpty]: ExistenceOperatorHandler,\n  [Operators.NullOrWhiteSpace]: ExistenceOperatorHandler,\n  [Operators.NotNullOrWhiteSpace]: ExistenceOperatorHandler,\n\n  // Date operators\n  [Operators.DateAfter]: DateOperatorHandler,\n  [Operators.DateBefore]: DateOperatorHandler,\n  [Operators.DateEquals]: DateOperatorHandler,\n  [Operators.DateBetween]: DateOperatorHandler,\n  [Operators.DateNotBetween]: DateOperatorHandler,\n  [Operators.DateAfterNow]: DateOperatorHandler,\n  [Operators.DateBeforeNow]: DateOperatorHandler,\n  [Operators.DateAfterOrEquals]: DateOperatorHandler,\n  [Operators.DateBeforeOrEquals]: DateOperatorHandler,\n\n  // Type validation\n  [Operators.String]: TypeValidationHandler,\n  [Operators.Number]: TypeValidationHandler,\n  [Operators.Boolean]: TypeValidationHandler,\n  [Operators.Array]: TypeValidationHandler,\n  [Operators.Object]: TypeValidationHandler,\n  [Operators.Email]: TypeValidationHandler,\n  [Operators.Url]: TypeValidationHandler,\n  [Operators.UUID]: TypeValidationHandler,\n  [Operators.Date]: TypeValidationHandler,\n\n  // String validation\n  [Operators.Alpha]: StringValidationHandler,\n  [Operators.AlphaNumeric]: StringValidationHandler,\n  [Operators.LowerCase]: StringValidationHandler,\n  [Operators.UpperCase]: StringValidationHandler,\n  [Operators.Matches]: StringValidationHandler,\n  [Operators.NotMatches]: StringValidationHandler,\n\n  // Number validation\n  [Operators.Positive]: NumberValidationHandler,\n  [Operators.Negative]: NumberValidationHandler,\n  [Operators.Zero]: NumberValidationHandler,\n  [Operators.Min]: NumberValidationHandler,\n  [Operators.Max]: NumberValidationHandler,\n  [Operators.Between]: NumberValidationHandler,\n  [Operators.NotBetween]: NumberValidationHandler,\n\n  // Length validation\n  [Operators.StringLength]: LengthValidationHandler,\n  [Operators.MinLength]: LengthValidationHandler,\n  [Operators.MaxLength]: LengthValidationHandler,\n  [Operators.LengthBetween]: LengthValidationHandler,\n  [Operators.NotLengthBetween]: LengthValidationHandler,\n\n  // Boolean validation\n  [Operators.Truthy]: BooleanValidationHandler,\n  [Operators.Falsy]: BooleanValidationHandler,\n  [Operators.BooleanString]: BooleanValidationHandler,\n  [Operators.BooleanNumber]: BooleanValidationHandler,\n};\n\nexport const OperatorHandler: React.FC<OperatorHandlerProps> = (props) => {\n  const Handler = operatorHandlers[props.operator] || ComparisonOperatorHandler;\n  return <Handler {...props} />;\n};\n"
  },
  {
    "path": "packages/builder/src/components/resizable-panel.tsx",
    "content": "import React, { useState, useRef, useEffect, useCallback } from \"react\";\nimport { cn } from \"../lib/utils\";\n\ninterface ResizablePanelProps {\n  defaultSize?: number;\n  minSize?: number;\n  maxSize?: number;\n  direction?: \"horizontal\" | \"vertical\";\n  onResize?: (size: number) => void;\n  children: [React.ReactNode, React.ReactNode];\n  className?: string;\n  handleClassName?: string;\n  persistId?: string;\n}\n\nexport const ResizablePanel: React.FC<ResizablePanelProps> = ({\n  defaultSize = 40,\n  minSize = 20,\n  maxSize = 80,\n  direction = \"horizontal\",\n  onResize,\n  children,\n  className,\n  handleClassName,\n  persistId,\n}) => {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const [size, setSize] = useState(() => {\n    if (persistId) {\n      const saved = localStorage.getItem(`resizable-panel-${persistId}`);\n      return saved ? Number.parseFloat(saved) : defaultSize;\n    }\n    return defaultSize;\n  });\n  const [isDragging, setIsDragging] = useState(false);\n\n  const handleMouseDown = useCallback((e: React.MouseEvent) => {\n    e.preventDefault();\n    setIsDragging(true);\n  }, []);\n\n  const handleMouseMove = useCallback(\n    (e: MouseEvent) => {\n      if (!isDragging || !containerRef.current) return;\n\n      const container = containerRef.current;\n      const rect = container.getBoundingClientRect();\n\n      let newSize: number;\n      if (direction === \"horizontal\") {\n        const position = ((e.clientX - rect.left) / rect.width) * 100;\n        newSize = Math.max(minSize, Math.min(maxSize, position));\n      } else {\n        const position = ((e.clientY - rect.top) / rect.height) * 100;\n        newSize = Math.max(minSize, Math.min(maxSize, position));\n      }\n\n      setSize(newSize);\n      onResize?.(newSize);\n\n      if (persistId) {\n        localStorage.setItem(\n          `resizable-panel-${persistId}`,\n          newSize.toString(),\n        );\n      }\n    },\n    [isDragging, direction, minSize, maxSize, onResize, persistId],\n  );\n\n  const handleMouseUp = useCallback(() => {\n    setIsDragging(false);\n  }, []);\n\n  useEffect(() => {\n    if (isDragging) {\n      document.addEventListener(\"mousemove\", handleMouseMove);\n      document.addEventListener(\"mouseup\", handleMouseUp);\n      document.body.style.cursor =\n        direction === \"horizontal\" ? \"col-resize\" : \"row-resize\";\n      document.body.style.userSelect = \"none\";\n\n      return () => {\n        document.removeEventListener(\"mousemove\", handleMouseMove);\n        document.removeEventListener(\"mouseup\", handleMouseUp);\n        document.body.style.cursor = \"\";\n        document.body.style.userSelect = \"\";\n      };\n    }\n  }, [isDragging, handleMouseMove, handleMouseUp, direction]);\n\n  const isHorizontal = direction === \"horizontal\";\n\n  return (\n    <div\n      ref={containerRef}\n      className={cn(\n        \"relative flex h-full w-full\",\n        isHorizontal ? \"flex-row\" : \"flex-col\",\n        className,\n      )}\n    >\n      {/* First Panel */}\n      <div\n        className={cn(\"overflow-hidden\", isHorizontal ? \"h-full\" : \"w-full\")}\n        style={{\n          [isHorizontal ? \"width\" : \"height\"]: `${size}%`,\n        }}\n      >\n        {children[0]}\n      </div>\n\n      {/* Resize Handle */}\n      <div\n        onMouseDown={handleMouseDown}\n        className={cn(\n          \"relative group flex items-center justify-center\",\n          isHorizontal ? \"w-1 cursor-col-resize\" : \"h-1 cursor-row-resize\",\n          \"hover:bg-primary/10 transition-colors\",\n          isDragging && \"bg-primary/20\",\n          handleClassName,\n        )}\n      >\n        {/* Visual indicator */}\n        <div\n          className={cn(\n            \"absolute rounded-full bg-border transition-all\",\n            \"group-hover:bg-primary/50\",\n            isDragging && \"bg-primary\",\n            isHorizontal\n              ? \"h-8 w-1 group-hover:w-1.5\"\n              : \"w-8 h-1 group-hover:h-1.5\",\n          )}\n        />\n\n        {/* Draggable area */}\n        <div\n          className={cn(\n            \"absolute\",\n            isHorizontal ? \"inset-y-0 -inset-x-1\" : \"inset-x-0 -inset-y-1\",\n          )}\n        />\n      </div>\n\n      {/* Second Panel */}\n      <div\n        className={cn(\n          \"flex-1 overflow-hidden\",\n          isHorizontal ? \"h-full\" : \"w-full\",\n        )}\n      >\n        {children[1]}\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/rule-builder.tsx",
    "content": "import React, { useState, useEffect, useCallback } from \"react\";\nimport { RuleEditor } from \"./rule-editor\";\nimport { RuleViewer } from \"./rule-viewer\";\nimport { RuleEvaluator } from \"./rule-evaluator\";\nimport { TabsTrigger, TabsList, TabsContent, Tabs } from \"./ui/tabs\";\nimport { Button } from \"./ui/button\";\nimport { Card } from \"./ui/card\";\nimport { X, Settings, Play, Menu, Code } from \"lucide-react\";\nimport type { RuleBuilderProps } from \"../types\";\nimport { cn } from \"../lib/utils\";\nimport { ecommerceFields } from \"../data/sample-data\";\nimport { operatorConfigs } from \"../utils/operators\";\nimport { useUnifiedRuleStore } from \"../stores/unified-rule-store\";\n\n// Extract default props to prevent infinite re-renders\nconst defaultFields = ecommerceFields;\nconst defaultOperators = operatorConfigs;\n\n/**\n * Modern, responsive Rule Builder with mobile-first design\n *\n * Design Philosophy:\n * - Mobile-first responsive design\n * - Progressive disclosure of complexity\n * - Clear visual hierarchy\n * - Consistent dark mode support\n * - Optimized for different screen sizes\n */\nexport const RuleBuilder: React.FC<RuleBuilderProps> = ({\n  className,\n  showViewer = true,\n  viewerPosition = \"right\",\n  theme,\n  fields = defaultFields,\n  operators = defaultOperators,\n  onRuleChange,\n  readOnly = false,\n}) => {\n  const rule = useUnifiedRuleStore((state) => state.rule);\n  const [isMobile, setIsMobile] = useState(false);\n  const [sidebarOpen, setSidebarOpen] = useState(false);\n  const [activeTab, setActiveTab] = useState<\"json\" | \"evaluator\">(\"json\");\n\n  // Handle rule changes\n  useEffect(() => {\n    if (onRuleChange) {\n      onRuleChange(rule);\n    }\n  }, [rule, onRuleChange]);\n\n  // Handle responsive behavior\n  useEffect(() => {\n    const checkIsMobile = () => {\n      setIsMobile(window.innerWidth < 1024);\n      if (window.innerWidth >= 1024) {\n        setSidebarOpen(false);\n      }\n    };\n\n    checkIsMobile();\n    window.addEventListener(\"resize\", checkIsMobile);\n    return () => window.removeEventListener(\"resize\", checkIsMobile);\n  }, []);\n\n  // Toggle sidebar for mobile\n  const toggleSidebar = useCallback(() => {\n    setSidebarOpen(!sidebarOpen);\n  }, [sidebarOpen]);\n\n  // Close sidebar on mobile when clicking outside or on action\n  const closeSidebar = useCallback(() => {\n    if (isMobile) {\n      setSidebarOpen(false);\n    }\n  }, [isMobile]);\n\n  // Custom CSS properties for theming\n  const themeStyles = theme\n    ? ({\n        \"--primary\": theme.colors?.primary,\n        \"--secondary\": theme.colors?.secondary,\n        \"--destructive\": theme.colors?.destructive,\n        \"--muted\": theme.colors?.muted,\n        \"--accent\": theme.colors?.accent,\n        \"--background\": theme.colors?.background,\n        \"--foreground\": theme.colors?.foreground,\n        \"--card\": theme.colors?.card,\n        \"--border\": theme.colors?.border,\n        fontFamily: theme.fontFamily,\n      } as React.CSSProperties)\n    : undefined;\n\n  // Mobile-first layout (bottom tabs)\n  if (isMobile && viewerPosition === \"bottom\") {\n    return (\n      <div\n        className={cn(\"flex flex-col h-full min-h-0\", className)}\n        style={themeStyles}\n      >\n        {/* Main Content Area */}\n        <div className=\"flex-1 min-h-0 p-4 pb-2\">\n          <RuleEditor\n            fields={fields}\n            operators={operators}\n            readOnly={readOnly}\n            className=\"h-full\"\n          />\n        </div>\n\n        {/* Bottom Tabs for Mobile */}\n        {showViewer && (\n          <div className=\"border-t bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60\">\n            <Tabs\n              value={activeTab}\n              onValueChange={setActiveTab as any}\n              className=\"w-full\"\n            >\n              <TabsList className=\"grid grid-cols-2 w-full h-12 bg-transparent p-1\">\n                <TabsTrigger\n                  value=\"json\"\n                  className=\"flex items-center gap-2 text-sm data-[state=active]:bg-accent\"\n                >\n                  <Code className=\"h-4 w-4\" />\n                  <span className=\"hidden xs:inline\">JSON</span>\n                </TabsTrigger>\n                <TabsTrigger\n                  value=\"evaluator\"\n                  className=\"flex items-center gap-2 text-sm data-[state=active]:bg-accent\"\n                >\n                  <Play className=\"h-4 w-4\" />\n                  <span className=\"hidden xs:inline\">Evaluator</span>\n                </TabsTrigger>\n              </TabsList>\n              <div className=\"max-h-80 min-h-[200px]\">\n                <TabsContent value=\"json\" className=\"m-0 p-4\">\n                  <RuleViewer\n                    rule={rule}\n                    syntaxHighlight\n                    collapsible\n                    defaultCollapsed={false}\n                  />\n                </TabsContent>\n                <TabsContent value=\"evaluator\" className=\"m-0 p-4\">\n                  <RuleEvaluator />\n                </TabsContent>\n              </div>\n            </Tabs>\n          </div>\n        )}\n      </div>\n    );\n  }\n\n  // Mobile layout with overlay sidebar\n  if (isMobile) {\n    return (\n      <div\n        className={cn(\"relative h-full flex flex-col\", className)}\n        style={themeStyles}\n      >\n        {/* Mobile Header */}\n        <div className=\"flex items-center justify-between p-4 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60\">\n          <h1 className=\"font-semibold text-lg\">Rule Builder</h1>\n          {showViewer && (\n            <Button\n              variant=\"ghost\"\n              size=\"sm\"\n              onClick={toggleSidebar}\n              className=\"lg:hidden\"\n            >\n              {sidebarOpen ? (\n                <X className=\"h-5 w-5\" />\n              ) : (\n                <Menu className=\"h-5 w-5\" />\n              )}\n            </Button>\n          )}\n        </div>\n\n        {/* Main Content */}\n        <div className=\"flex-1 min-h-0 p-4\">\n          <RuleEditor\n            fields={fields}\n            operators={operators}\n            readOnly={readOnly}\n            className=\"h-full\"\n          />\n        </div>\n\n        {/* Mobile Sidebar Overlay */}\n        {showViewer && (\n          <>\n            {/* Backdrop */}\n            {sidebarOpen && (\n              <div\n                className=\"fixed inset-0 bg-black/20 backdrop-blur-sm z-40 lg:hidden\"\n                onClick={closeSidebar}\n              />\n            )}\n\n            {/* Sidebar */}\n            <div\n              className={cn(\n                \"fixed top-0 right-0 h-full w-80 max-w-[85vw] bg-background border-l shadow-2xl transform transition-transform duration-300 ease-in-out z-50 lg:hidden\",\n                sidebarOpen ? \"translate-x-0\" : \"translate-x-full\",\n              )}\n            >\n              <div className=\"flex flex-col h-full\">\n                {/* Sidebar Header */}\n                <div className=\"flex items-center justify-between p-4 border-b\">\n                  <h2 className=\"font-medium\">Tools</h2>\n                  <Button variant=\"ghost\" size=\"sm\" onClick={closeSidebar}>\n                    <X className=\"h-4 w-4\" />\n                  </Button>\n                </div>\n\n                {/* Sidebar Content */}\n                <div className=\"flex-1 min-h-0\">\n                  <Tabs\n                    value={activeTab}\n                    onValueChange={setActiveTab as any}\n                    className=\"h-full flex flex-col\"\n                  >\n                    <TabsList className=\"grid grid-cols-2 m-4 mb-2\">\n                      <TabsTrigger\n                        value=\"json\"\n                        className=\"flex items-center gap-2 text-sm\"\n                      >\n                        <Code className=\"h-4 w-4\" />\n                        JSON\n                      </TabsTrigger>\n                      <TabsTrigger\n                        value=\"evaluator\"\n                        className=\"flex items-center gap-2 text-sm\"\n                      >\n                        <Play className=\"h-4 w-4\" />\n                        Evaluator\n                      </TabsTrigger>\n                    </TabsList>\n                    <div className=\"flex-1 min-h-0 px-4 pb-4\">\n                      <TabsContent value=\"json\" className=\"h-full m-0\">\n                        <RuleViewer\n                          rule={rule}\n                          syntaxHighlight\n                          collapsible\n                          defaultCollapsed={false}\n                          className=\"h-full\"\n                        />\n                      </TabsContent>\n                      <TabsContent value=\"evaluator\" className=\"h-full m-0\">\n                        <RuleEvaluator className=\"h-full\" />\n                      </TabsContent>\n                    </div>\n                  </Tabs>\n                </div>\n              </div>\n            </div>\n          </>\n        )}\n      </div>\n    );\n  }\n\n  // Desktop layout with resizable panels\n  return (\n    <div className={cn(\"h-full flex\", className)} style={themeStyles}>\n      {/* Main Panel */}\n      <div className={cn(\"flex-1 min-w-0\", showViewer ? \"pr-1\" : \"\")}>\n        <RuleEditor\n          fields={fields}\n          operators={operators}\n          readOnly={readOnly}\n          className=\"h-full\"\n        />\n      </div>\n\n      {/* Desktop Right Panel */}\n      {showViewer && (\n        <div className=\"w-96 min-w-0 pl-1\">\n          <Card className=\"h-full flex flex-col shadow-lg border-l-2 border-border/50\">\n            {/* Panel Header */}\n            <div className=\"flex items-center justify-between p-4 border-b bg-muted/30\">\n              <div className=\"flex items-center gap-2\">\n                <Settings className=\"h-4 w-4 text-muted-foreground\" />\n                <h3 className=\"font-semibold text-sm\">Rule Tools</h3>\n              </div>\n              <div className=\"flex items-center gap-1\">\n                <Button\n                  variant={activeTab === \"json\" ? \"secondary\" : \"ghost\"}\n                  size=\"sm\"\n                  onClick={() => setActiveTab(\"json\")}\n                  className=\"h-8 px-2\"\n                >\n                  <Code className=\"h-3 w-3\" />\n                </Button>\n                <Button\n                  variant={activeTab === \"evaluator\" ? \"secondary\" : \"ghost\"}\n                  size=\"sm\"\n                  onClick={() => setActiveTab(\"evaluator\")}\n                  className=\"h-8 px-2\"\n                >\n                  <Play className=\"h-3 w-3\" />\n                </Button>\n              </div>\n            </div>\n\n            {/* Panel Content */}\n            <div className=\"flex-1 min-h-0 p-4\">\n              <Tabs\n                value={activeTab}\n                onValueChange={setActiveTab as any}\n                className=\"h-full\"\n              >\n                <TabsContent value=\"json\" className=\"h-full m-0\">\n                  <RuleViewer\n                    rule={rule}\n                    syntaxHighlight\n                    collapsible\n                    defaultCollapsed={false}\n                    className=\"h-full\"\n                  />\n                </TabsContent>\n                <TabsContent value=\"evaluator\" className=\"h-full m-0\">\n                  <RuleEvaluator className=\"h-full\" />\n                </TabsContent>\n              </Tabs>\n            </div>\n          </Card>\n        </div>\n      )}\n    </div>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/rule-editor.tsx",
    "content": "import React, { useState, useCallback } from \"react\";\nimport { CardContent, Card } from \"./ui/card\";\nimport { Button } from \"./ui/button\";\nimport { Badge } from \"./ui/badge\";\nimport { Separator } from \"./ui/separator\";\nimport {\n  Undo2,\n  Sparkles,\n  Settings,\n  Redo2,\n  Plus,\n  Layers,\n  Download,\n  ChevronDown,\n} from \"lucide-react\";\nimport { ConditionGroup } from \"./condition-group\";\nimport { RuleImportModal } from \"./rule-import-modal\";\nimport { HistoryViewer } from \"./history-viewer\";\nimport { useRuleBuilder } from \"../stores/unified-rule-store\";\nimport { ConditionTypes } from \"@usex/rule-engine\";\nimport type { RuleEditorProps } from \"../types\";\nimport { cn } from \"../lib/utils\";\n\n// Extract default props to prevent infinite re-renders\nconst defaultFields: any[] = [];\nconst defaultOperators: any[] = [];\n\n/**\n * Modern Rule Editor with enhanced UX and mobile-first design\n *\n * Design Features:\n * - Progressive disclosure of complexity\n * - Clear visual hierarchy with proper spacing\n * - Mobile-optimized toolbar with smart grouping\n * - Enhanced empty state with better onboarding\n * - Consistent dark mode support\n * - Improved accessibility\n */\nexport const RuleEditor: React.FC<RuleEditorProps> = ({\n  className,\n  readOnly = false,\n  fields = defaultFields,\n  operators = defaultOperators,\n}) => {\n  const {\n    state,\n    addCondition,\n    updateCondition,\n    importRule,\n    exportRule,\n    undo,\n    redo,\n    canUndo,\n    canRedo,\n  } = useRuleBuilder();\n\n  const [showAdvancedTools, setShowAdvancedTools] = useState(false);\n\n  // Determine if we have conditions to display\n  const hasConditions = React.useMemo(() => {\n    if (!state.rule.conditions) {\n      return false;\n    }\n\n    const conditions = state.rule.conditions;\n\n    // Handle both single condition and array of conditions\n    if (Array.isArray(conditions)) {\n      return conditions.length > 0;\n    }\n\n    // Single condition object\n    const condition = conditions as any;\n\n    // Check if the conditions object is empty (no keys)\n    if (Object.keys(condition).length === 0) {\n      return false;\n    }\n\n    // If there are condition type keys (and, or, none), we have conditions\n    // even if the arrays are empty (user can add constraints to them)\n    return !!(\n      condition.and !== undefined ||\n      condition.or !== undefined ||\n      condition.none !== undefined\n    );\n  }, [state.rule.conditions]);\n\n  // Add root condition handler\n  const handleAddRootCondition = useCallback(() => {\n    addCondition(\"\", ConditionTypes.AND);\n  }, [addCondition]);\n\n  // Export rule as JSON\n  const handleExport = useCallback(() => {\n    const rule = exportRule();\n    const json = JSON.stringify(rule, null, 2);\n    const blob = new Blob([json], { type: \"application/json\" });\n    const url = URL.createObjectURL(blob);\n    const a = document.createElement(\"a\");\n    a.href = url;\n    a.download = `rule-${Date.now()}.json`;\n    document.body.appendChild(a);\n    a.click();\n    document.body.removeChild(a);\n    URL.revokeObjectURL(url);\n  }, [exportRule]);\n\n  // Get condition statistics for display\n  const conditionStats = React.useMemo(() => {\n    if (!hasConditions) return null;\n\n    let totalConditions = 0;\n    let totalConstraints = 0;\n\n    const countConditions = (condition: any): void => {\n      if (Array.isArray(condition)) {\n        condition.forEach(countConditions);\n        return;\n      }\n\n      if (condition?.and) {\n        totalConditions++;\n        condition.and.forEach((item: any) => {\n          if (item.field) totalConstraints++;\n          else countConditions(item);\n        });\n      }\n      if (condition?.or) {\n        totalConditions++;\n        condition.or.forEach((item: any) => {\n          if (item.field) totalConstraints++;\n          else countConditions(item);\n        });\n      }\n      if (condition?.none) {\n        totalConditions++;\n        condition.none.forEach((item: any) => {\n          if (item.field) totalConstraints++;\n          else countConditions(item);\n        });\n      }\n    };\n\n    countConditions(state.rule.conditions);\n    return { totalConditions, totalConstraints };\n  }, [state.rule.conditions, hasConditions]);\n\n  return (\n    <Card className={cn(\"h-full flex flex-col shadow-sm\", className)}>\n      {/* Modern Header with Progressive Disclosure */}\n      <div className=\"flex flex-col gap-3 p-4 sm:p-6 border-b bg-gradient-to-r from-background via-muted/5 to-background\">\n        {/* Title and Stats Row */}\n        <div className=\"flex items-center justify-between\">\n          <div className=\"flex items-center gap-3\">\n            <div className=\"flex items-center gap-2\">\n              <div className=\"p-2 rounded-lg bg-primary/10 border border-primary/20\">\n                <Layers className=\"h-4 w-4 text-primary\" />\n              </div>\n              <div>\n                <h2 className=\"font-semibold text-lg text-foreground\">\n                  Rule Editor\n                </h2>\n                {conditionStats && (\n                  <div className=\"flex items-center gap-2 mt-1\">\n                    <Badge variant=\"secondary\" className=\"text-xs px-2 py-0.5\">\n                      {conditionStats.totalConditions} groups\n                    </Badge>\n                    <Badge variant=\"outline\" className=\"text-xs px-2 py-0.5\">\n                      {conditionStats.totalConstraints} rules\n                    </Badge>\n                  </div>\n                )}\n              </div>\n            </div>\n          </div>\n\n          {/* Quick Actions - Always Visible */}\n          {!readOnly && (\n            <div className=\"flex items-center gap-1\">\n              <Button\n                variant=\"ghost\"\n                size=\"sm\"\n                onClick={undo}\n                disabled={!canUndo()}\n                title=\"Undo (Ctrl+Z)\"\n                className=\"h-8 w-8 p-0\"\n              >\n                <Undo2 className=\"h-4 w-4\" />\n              </Button>\n              <Button\n                variant=\"ghost\"\n                size=\"sm\"\n                onClick={redo}\n                disabled={!canRedo()}\n                title=\"Redo (Ctrl+Y)\"\n                className=\"h-8 w-8 p-0\"\n              >\n                <Redo2 className=\"h-4 w-4\" />\n              </Button>\n              <Separator orientation=\"vertical\" className=\"h-6 mx-1\" />\n              <Button\n                variant=\"ghost\"\n                size=\"sm\"\n                onClick={() => setShowAdvancedTools(!showAdvancedTools)}\n                className=\"h-8 px-2\"\n              >\n                <Settings className=\"h-4 w-4\" />\n                <ChevronDown\n                  className={cn(\n                    \"h-3 w-3 ml-1 transition-transform duration-200\",\n                    showAdvancedTools && \"rotate-180\",\n                  )}\n                />\n              </Button>\n            </div>\n          )}\n        </div>\n\n        {/* Advanced Tools - Progressive Disclosure */}\n        {!readOnly && showAdvancedTools && (\n          <div className=\"flex flex-wrap items-center gap-2 pt-2 border-t\">\n            <div className=\"flex items-center gap-1\">\n              <HistoryViewer />\n              <RuleImportModal onImport={importRule} />\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                onClick={handleExport}\n                title=\"Export Rule JSON\"\n                className=\"h-8\"\n              >\n                <Download className=\"h-4 w-4 mr-1\" />\n                <span className=\"hidden sm:inline\">Export</span>\n              </Button>\n            </div>\n          </div>\n        )}\n      </div>\n\n      {/* Main Content Area */}\n      <CardContent className=\"flex-1 min-h-0 p-4 sm:p-6\">\n        {!hasConditions ? (\n          /* Enhanced Empty State */\n          <div className=\"h-full flex items-center justify-center\">\n            <div className=\"text-center max-w-md mx-auto space-y-6\">\n              {/* Visual Element */}\n              <div className=\"relative\">\n                <div className=\"w-16 h-16 mx-auto rounded-2xl bg-gradient-to-br from-primary/20 via-accent/10 to-secondary/20 border-2 border-dashed border-primary/30 flex items-center justify-center\">\n                  <Sparkles className=\"h-7 w-7 text-primary/70\" />\n                </div>\n                <div className=\"absolute -top-1 -right-1 w-6 h-6 rounded-full bg-accent/20 border border-accent/40\" />\n                <div className=\"absolute -bottom-1 -left-1 w-4 h-4 rounded-full bg-secondary/20 border border-secondary/40\" />\n              </div>\n\n              {/* Content */}\n              <div className=\"space-y-3\">\n                <h3 className=\"text-xl font-semibold text-foreground\">\n                  Create Your First Rule\n                </h3>\n                <p className=\"text-muted-foreground text-sm leading-relaxed\">\n                  Start building powerful business logic with condition groups.\n                  Add rules that evaluate data and trigger actions based on your\n                  criteria.\n                </p>\n              </div>\n\n              {/* Call to Action */}\n              {!readOnly && (\n                <div className=\"space-y-3\">\n                  <Button\n                    onClick={handleAddRootCondition}\n                    size=\"lg\"\n                    className=\"h-11 px-6 font-medium shadow-sm hover:shadow-md transition-all duration-200\"\n                  >\n                    <Plus className=\"h-4 w-4 mr-2\" />\n                    Add Condition Group\n                  </Button>\n\n                  <div className=\"flex items-center justify-center gap-4 text-xs text-muted-foreground\">\n                    <div className=\"flex items-center gap-1\">\n                      <div className=\"w-2 h-2 rounded-full bg-green-500/60\" />\n                      <span>AND logic</span>\n                    </div>\n                    <div className=\"flex items-center gap-1\">\n                      <div className=\"w-2 h-2 rounded-full bg-blue-500/60\" />\n                      <span>OR logic</span>\n                    </div>\n                    <div className=\"flex items-center gap-1\">\n                      <div className=\"w-2 h-2 rounded-full bg-red-500/60\" />\n                      <span>NOT logic</span>\n                    </div>\n                  </div>\n                </div>\n              )}\n            </div>\n          </div>\n        ) : (\n          /* Condition Groups */\n          <div className=\"h-full overflow-auto\">\n            <div className=\"space-y-4 pb-4\">\n              <ConditionGroup\n                key=\"root-condition\"\n                condition={state.rule.conditions as any}\n                path=\"\"\n                fields={fields}\n                operators={operators}\n                readOnly={readOnly}\n                onUpdate={(updatedCondition) =>\n                  updateCondition(\"\", updatedCondition)\n                }\n                onRemove={() => {\n                  // Reset to empty condition\n                  addCondition(\"\", ConditionTypes.AND);\n                }}\n              />\n            </div>\n          </div>\n        )}\n      </CardContent>\n\n      {/* Status Bar for Desktop */}\n      {hasConditions && (\n        <div className=\"hidden sm:flex items-center justify-between px-6 py-3 border-t bg-muted/20 text-xs text-muted-foreground\">\n          <div className=\"flex items-center gap-4\">\n            <span>Status: Active</span>\n            {state.isDirty && (\n              <Badge variant=\"secondary\" className=\"text-xs\">\n                Unsaved changes\n              </Badge>\n            )}\n          </div>\n          <div className=\"flex items-center gap-4\">\n            <span>Last modified: Now</span>\n            <span>•</span>\n            <span>{JSON.stringify(state.rule).length} bytes</span>\n          </div>\n        </div>\n      )}\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/rule-evaluator.tsx",
    "content": "import type {\n  EvaluationResult,\n  Constraint,\n  Condition,\n} from \"@usex/rule-engine\";\nimport { RuleEngine } from \"@usex/rule-engine\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Zap,\n  XCircle,\n  Play,\n  Info,\n  FileJson,\n  EyeOff,\n  Eye,\n  Cpu,\n  Code,\n  ChevronRight,\n  ChevronDown,\n  CheckCircle2,\n  AlertCircle,\n  Activity,\n} from \"lucide-react\";\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport { sampleEcommerceData } from \"../data/sample-data\";\nimport { useKeyboardShortcuts } from \"../hooks/use-keyboard-shortcuts\";\nimport { cn } from \"../lib/utils\";\nimport { useRuleBuilder } from \"../stores/unified-rule-store\";\nimport { EditableJsonViewer } from \"./editable-json-viewer\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Label } from \"./ui/label\";\nimport { ScrollArea } from \"./ui/scroll-area\";\nimport { Switch } from \"./ui/switch\";\nimport { TabsTrigger, TabsList, TabsContent, Tabs } from \"./ui/tabs\";\nimport {\n  TooltipTrigger,\n  TooltipProvider,\n  TooltipContent,\n  Tooltip,\n} from \"./ui/tooltip\";\n\ninterface EvaluationDetails {\n  condition: Condition;\n  path: string;\n  result: boolean;\n  message?: string;\n  constraints?: Array<{\n    constraint: Constraint;\n    passed: boolean;\n    actualValue?: any;\n    message?: string;\n  }>;\n  subConditions?: EvaluationDetails[];\n}\n\ninterface RuleEvaluatorProps {\n  className?: string;\n  defaultSampleData?: any;\n  onEvaluationChange?: (result: EvaluationResult | null) => void;\n}\n\n/**\n * Modern Rule Evaluator with enhanced UX and mobile-optimized design\n *\n * Features:\n * - Clean, modern interface with proper visual hierarchy\n * - Mobile-first responsive design\n * - Enhanced dark mode support\n * - Real-time evaluation with performance indicators\n * - Progressive disclosure of complex information\n * - Accessible design with proper ARIA labels\n */\nexport const RuleEvaluator: React.FC<RuleEvaluatorProps> = ({\n  className,\n  defaultSampleData = sampleEcommerceData,\n  onEvaluationChange,\n}) => {\n  const { state } = useRuleBuilder();\n  const rule = state.rule;\n  const [isLiveMode, setIsLiveMode] = useState(false);\n  const [showDetails, setShowDetails] = useState(false);\n  const [sampleData, setSampleData] = useState(defaultSampleData);\n  const [evaluationResult, setEvaluationResult] =\n    useState<EvaluationResult | null>(null);\n  const [evaluationDetails, setEvaluationDetails] = useState<\n    EvaluationDetails[]\n  >([]);\n  const [isEvaluating, setIsEvaluating] = useState(false);\n  const [error, setError] = useState<string | null>(null);\n  const [expandedPaths, setExpandedPaths] = useState<Set<string>>(\n    () => new Set(),\n  );\n  const [activeTab, setActiveTab] = useState<\"result\" | \"details\" | \"data\">(\n    \"result\",\n  );\n\n  // Helper to get value by path\n  const getValueByPath = (obj: any, path: string): any => {\n    try {\n      return path.split(\".\").reduce((curr, key) => {\n        if (key.includes(\"[\") && key.includes(\"]\")) {\n          const [arrayKey, indexStr] = key.split(\"[\");\n          const index = Number.parseInt(indexStr.replace(\"]\", \"\"));\n          return curr?.[arrayKey]?.[index];\n        }\n        return curr?.[key];\n      }, obj);\n    } catch {\n      return undefined;\n    }\n  };\n\n  // Evaluate individual constraint (defined first to avoid use-before-define)\n  const evaluateConstraint = useCallback(\n    (\n      constraint: Constraint,\n      data: any,\n    ): {\n      constraint: Constraint;\n      passed: boolean;\n      actualValue?: any;\n      message?: string;\n    } => {\n      try {\n        // Extract the actual value from data using the field path\n        const actualValue = getValueByPath(data, constraint.field);\n\n        // Simple evaluation logic - in real implementation, this would use the rule engine\n        let passed = false;\n\n        // This is a simplified version - the actual evaluation would be done by the rule engine\n        switch (constraint.operator) {\n          case \"equals\":\n            passed = actualValue === constraint.value;\n            break;\n          case \"not-equals\":\n            passed = actualValue !== constraint.value;\n            break;\n          case \"greater-than\":\n            passed = actualValue > (constraint.value ?? 0);\n            break;\n          case \"less-than\":\n            passed = actualValue < (constraint.value ?? 0);\n            break;\n          case \"contains\":\n            passed = actualValue?.includes?.(constraint.value) || false;\n            break;\n          case \"exists\":\n            passed = actualValue !== undefined && actualValue !== null;\n            break;\n          case \"not-exists\":\n            passed = actualValue === undefined || actualValue === null;\n            break;\n          default:\n            // For other operators, we'd need the actual rule engine evaluation\n            passed = false;\n        }\n\n        return {\n          constraint,\n          passed,\n          actualValue,\n          message: constraint.message,\n        };\n      } catch {\n        return {\n          constraint,\n          passed: false,\n          message: \"Error evaluating constraint\",\n        };\n      }\n    },\n    [],\n  );\n\n  // Evaluate condition details for visualization\n  const evaluateConditionDetails = useCallback(\n    (\n      conditions: Condition | Condition[],\n      data: any,\n      parentPath: string,\n    ): EvaluationDetails | EvaluationDetails[] => {\n      if (Array.isArray(conditions)) {\n        return conditions.map((cond, index) =>\n          evaluateConditionDetails(cond, data, `${parentPath}[${index}]`),\n        ) as EvaluationDetails[];\n      }\n\n      const condition = conditions;\n      const path = parentPath || \"root\";\n      const details: EvaluationDetails = {\n        condition,\n        path,\n        result: false,\n        constraints: [],\n        subConditions: [],\n      };\n\n      // Evaluate AND conditions\n      if (condition.and) {\n        const andResults: EvaluationDetails[] = [];\n        let allPassed = true;\n\n        for (let i = 0; i < condition.and.length; i++) {\n          const item = condition.and[i];\n          const itemPath = `${path}.and[${i}]`;\n\n          if (\"field\" in item) {\n            // It's a constraint\n            const constraintResult = evaluateConstraint(\n              item as Constraint,\n              data,\n            );\n            details.constraints?.push(constraintResult);\n            if (!constraintResult.passed) allPassed = false;\n          } else {\n            // It's a sub-condition\n            const subResult = evaluateConditionDetails(\n              item as Condition,\n              data,\n              itemPath,\n            );\n            andResults.push(subResult as EvaluationDetails);\n            if (!(subResult as EvaluationDetails).result) allPassed = false;\n          }\n        }\n\n        details.result = allPassed;\n        details.subConditions = andResults;\n      }\n\n      // Evaluate OR conditions\n      else if (condition.or) {\n        const orResults: EvaluationDetails[] = [];\n        let anyPassed = false;\n\n        for (let i = 0; i < condition.or.length; i++) {\n          const item = condition.or[i];\n          const itemPath = `${path}.or[${i}]`;\n\n          if (\"field\" in item) {\n            // It's a constraint\n            const constraintResult = evaluateConstraint(\n              item as Constraint,\n              data,\n            );\n            details.constraints?.push(constraintResult);\n            if (constraintResult.passed) anyPassed = true;\n          } else {\n            // It's a sub-condition\n            const subResult = evaluateConditionDetails(\n              item as Condition,\n              data,\n              itemPath,\n            );\n            orResults.push(subResult as EvaluationDetails);\n            if ((subResult as EvaluationDetails).result) anyPassed = true;\n          }\n        }\n\n        details.result = anyPassed;\n        details.subConditions = orResults;\n      }\n\n      // Evaluate NONE conditions\n      else if (condition.none) {\n        const noneResults: EvaluationDetails[] = [];\n        let nonePassed = true;\n\n        for (let i = 0; i < condition.none.length; i++) {\n          const item = condition.none[i];\n          const itemPath = `${path}.none[${i}]`;\n\n          if (\"field\" in item) {\n            // It's a constraint\n            const constraintResult = evaluateConstraint(\n              item as Constraint,\n              data,\n            );\n            details.constraints?.push({\n              ...constraintResult,\n              passed: !constraintResult.passed, // Invert for NONE\n            });\n            if (constraintResult.passed) nonePassed = false;\n          } else {\n            // It's a sub-condition\n            const subResult = evaluateConditionDetails(\n              item as Condition,\n              data,\n              itemPath,\n            );\n            noneResults.push(subResult as EvaluationDetails);\n            if ((subResult as EvaluationDetails).result) nonePassed = false;\n          }\n        }\n\n        details.result = nonePassed;\n        details.subConditions = noneResults;\n      }\n\n      return details;\n    },\n    [evaluateConstraint],\n  );\n\n  // Evaluate rule function\n  const evaluateRule = useCallback(async () => {\n    if (!rule || !rule.conditions) {\n      setError(\"No rule to evaluate\");\n      return;\n    }\n\n    setIsEvaluating(true);\n    setError(null);\n\n    try {\n      // Evaluate the rule\n      const result = await RuleEngine.evaluate(rule, sampleData);\n      const evalResult = Array.isArray(result) ? result[0] : result;\n\n      setEvaluationResult(evalResult);\n\n      // Generate detailed evaluation info\n      const details = evaluateConditionDetails(rule.conditions, sampleData, \"\");\n      setEvaluationDetails(Array.isArray(details) ? details : [details]);\n\n      if (onEvaluationChange) {\n        onEvaluationChange(evalResult);\n      }\n    } catch (err) {\n      setError(err instanceof Error ? err.message : \"Evaluation failed\");\n      setEvaluationResult(null);\n      setEvaluationDetails([]);\n\n      if (onEvaluationChange) {\n        onEvaluationChange(null);\n      }\n    } finally {\n      setIsEvaluating(false);\n    }\n  }, [rule, sampleData, onEvaluationChange, evaluateConditionDetails]);\n\n  // Toggle live evaluation mode\n  const toggleLiveMode = useCallback(() => {\n    setIsLiveMode(!isLiveMode);\n  }, [isLiveMode]);\n\n  // Run evaluation once\n  const runEvaluationOnce = useCallback(() => {\n    evaluateRule();\n  }, [evaluateRule]);\n\n  // Setup keyboard shortcuts\n  useKeyboardShortcuts([\n    {\n      key: \"e\",\n      ctrl: true,\n      handler: toggleLiveMode,\n      description: \"Toggle live evaluation\",\n    },\n    {\n      key: \"e\",\n      ctrl: true,\n      shift: true,\n      handler: runEvaluationOnce,\n      description: \"Run evaluation once\",\n    },\n  ]);\n\n  // Live evaluation effect\n  useEffect(() => {\n    if (isLiveMode) {\n      evaluateRule();\n    }\n  }, [isLiveMode, rule, sampleData, evaluateRule]);\n\n  // Toggle expanded state for a path\n  const toggleExpanded = useCallback((path: string) => {\n    setExpandedPaths((prev) => {\n      const newSet = new Set(prev);\n      if (newSet.has(path)) {\n        newSet.delete(path);\n      } else {\n        newSet.add(path);\n      }\n      return newSet;\n    });\n  }, []);\n\n  // Get condition type label\n  const getConditionType = (condition: Condition): string => {\n    if (condition.and) return `AND (${condition.and.length} conditions)`;\n    if (condition.or) return `OR (${condition.or.length} conditions)`;\n    if (condition.none) return `NONE (${condition.none.length} conditions)`;\n    return \"Condition\";\n  };\n\n  // Render evaluation details recursively\n  const renderEvaluationDetails = (\n    details: EvaluationDetails,\n    depth = 0,\n  ): React.ReactNode => {\n    const isExpanded = expandedPaths.has(details.path);\n    const hasChildren =\n      (details.subConditions?.length || 0) > 0 ||\n      (details.constraints?.length || 0) > 0;\n\n    return (\n      <div key={details.path} className=\"relative\">\n        <div\n          className={cn(\n            \"flex items-center gap-2 py-2 px-3 rounded-md transition-colors cursor-pointer hover:bg-accent\",\n            depth > 0 && \"ml-6\",\n            details.result\n              ? \"bg-green-50 dark:bg-green-950/20\"\n              : \"bg-red-50 dark:bg-red-950/20\",\n          )}\n          onClick={() => hasChildren && toggleExpanded(details.path)}\n        >\n          {hasChildren && (\n            <button type=\"button\" className=\"p-0.5\">\n              {isExpanded ? (\n                <ChevronDown className=\"h-4 w-4\" />\n              ) : (\n                <ChevronRight className=\"h-4 w-4\" />\n              )}\n            </button>\n          )}\n\n          <div className=\"flex items-center gap-2 flex-1\">\n            {details.result ? (\n              <CheckCircle2 className=\"h-4 w-4 text-green-500\" />\n            ) : (\n              <XCircle className=\"h-4 w-4 text-red-500\" />\n            )}\n\n            <span className=\"text-sm font-medium\">\n              {getConditionType(details.condition)}\n            </span>\n\n            {details.condition.result && (\n              <Badge variant=\"outline\" className=\"ml-2 text-xs\">\n                Result: {JSON.stringify(details.condition.result.value)}\n              </Badge>\n            )}\n          </div>\n        </div>\n\n        <AnimatePresence>\n          {isExpanded && hasChildren && (\n            <motion.div\n              initial={{ opacity: 0, height: 0 }}\n              animate={{ opacity: 1, height: \"auto\" }}\n              exit={{ opacity: 0, height: 0 }}\n              transition={{ duration: 0.2 }}\n              className=\"overflow-hidden\"\n            >\n              {/* Render constraints */}\n              {details.constraints?.map((constraint, index) => (\n                <div\n                  key={`${details.path}-constraint-${index}`}\n                  className={cn(\n                    \"flex items-center gap-2 py-1.5 px-3 ml-8 text-sm\",\n                    constraint.passed ? \"text-green-600\" : \"text-red-600\",\n                  )}\n                >\n                  {constraint.passed ? (\n                    <CheckCircle2 className=\"h-3 w-3\" />\n                  ) : (\n                    <XCircle className=\"h-3 w-3\" />\n                  )}\n                  <span className=\"font-mono text-xs\">\n                    {constraint.constraint.field}{\" \"}\n                    {constraint.constraint.operator}{\" \"}\n                    {JSON.stringify(constraint.constraint.value)}\n                  </span>\n                  {constraint.actualValue !== undefined && (\n                    <span className=\"text-xs text-muted-foreground ml-2\">\n                      (actual: {JSON.stringify(constraint.actualValue)})\n                    </span>\n                  )}\n                </div>\n              ))}\n\n              {/* Render sub-conditions */}\n              {details.subConditions?.map((subDetail) => (\n                <div key={subDetail.path} className=\"ml-4\">\n                  {renderEvaluationDetails(subDetail, depth + 1)}\n                </div>\n              ))}\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </div>\n    );\n  };\n\n  // Result indicator component\n  const ResultIndicator = () => {\n    if (!evaluationResult && !error) return null;\n\n    return (\n      <motion.div\n        initial={{ scale: 0 }}\n        animate={{ scale: 1 }}\n        transition={{ type: \"spring\", stiffness: 500, damping: 30 }}\n        className={cn(\n          \"flex items-center gap-2 px-3 py-1.5 rounded-full text-sm font-medium shadow-sm backdrop-blur-sm border\",\n          evaluationResult?.isPassed\n            ? \"bg-green-50 dark:bg-green-950/30 text-green-700 dark:text-green-300 border-green-200 dark:border-green-800\"\n            : \"bg-red-50 dark:bg-red-950/30 text-red-700 dark:text-red-300 border-red-200 dark:border-red-800\",\n        )}\n      >\n        {evaluationResult?.isPassed ? (\n          <>\n            <CheckCircle2 className=\"h-4 w-4\" />\n            <span>Pass</span>\n          </>\n        ) : (\n          <>\n            <XCircle className=\"h-4 w-4\" />\n            <span>Fail</span>\n          </>\n        )}\n      </motion.div>\n    );\n  };\n\n  return (\n    <TooltipProvider>\n      <Card className={cn(\"h-full flex flex-col shadow-sm\", className)}>\n        {/* Modern Header */}\n        <CardHeader className=\"pb-4\">\n          <div className=\"flex items-center justify-between\">\n            <div className=\"flex items-center gap-3\">\n              <div className=\"p-2 rounded-lg bg-gradient-to-br from-blue-500/10 to-purple-500/10 border border-blue-200/50 dark:border-blue-800/50\">\n                <Cpu className=\"h-4 w-4 text-blue-600 dark:text-blue-400\" />\n              </div>\n              <div>\n                <h3 className=\"font-semibold text-foreground\">\n                  Rule Evaluator\n                </h3>\n                <p className=\"text-sm text-muted-foreground\">\n                  Test rules with live data evaluation\n                </p>\n              </div>\n            </div>\n            <ResultIndicator />\n          </div>\n        </CardHeader>\n\n        {/* Content Area */}\n        <CardContent className=\"flex-1 min-h-0 space-y-4 overflow-hidden\">\n          {/* Control Panel */}\n          <div className=\"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 p-3 bg-muted/30 rounded-lg border\">\n            {/* Live Mode Toggle */}\n            <div className=\"flex items-center gap-3\">\n              <Switch\n                id=\"live-mode\"\n                checked={isLiveMode}\n                onCheckedChange={setIsLiveMode}\n              />\n              <Label\n                htmlFor=\"live-mode\"\n                className=\"text-sm font-medium cursor-pointer\"\n              >\n                Live Mode\n              </Label>\n              <Tooltip>\n                <TooltipTrigger>\n                  <Info className=\"h-3.5 w-3.5 text-muted-foreground hover:text-foreground transition-colors\" />\n                </TooltipTrigger>\n                <TooltipContent side=\"bottom\">\n                  <p className=\"font-medium\">Ctrl/Cmd + E to toggle</p>\n                </TooltipContent>\n              </Tooltip>\n            </div>\n\n            {/* Control Buttons */}\n            <div className=\"flex items-center gap-2\">\n              <Button\n                variant={showDetails ? \"secondary\" : \"outline\"}\n                size=\"sm\"\n                onClick={() => setShowDetails(!showDetails)}\n                className=\"h-8\"\n              >\n                {showDetails ? (\n                  <>\n                    <EyeOff className=\"h-4 w-4 mr-1\" />\n                    <span className=\"hidden sm:inline\">Hide</span>\n                  </>\n                ) : (\n                  <>\n                    <Eye className=\"h-4 w-4 mr-1\" />\n                    <span className=\"hidden sm:inline\">Details</span>\n                  </>\n                )}\n              </Button>\n\n              {/* Run Once Button */}\n              {!isLiveMode && (\n                <Tooltip>\n                  <TooltipTrigger asChild>\n                    <Button\n                      size=\"sm\"\n                      onClick={runEvaluationOnce}\n                      disabled={isEvaluating}\n                      className=\"h-8\"\n                    >\n                      {isEvaluating ? (\n                        <motion.div\n                          animate={{ rotate: 360 }}\n                          transition={{\n                            duration: 1,\n                            repeat: Infinity,\n                            ease: \"linear\",\n                          }}\n                          className=\"mr-1\"\n                        >\n                          <Zap className=\"h-4 w-4\" />\n                        </motion.div>\n                      ) : (\n                        <Play className=\"h-4 w-4 mr-1\" />\n                      )}\n                      <span className=\"hidden sm:inline\">\n                        {isEvaluating ? \"Running...\" : \"Evaluate\"}\n                      </span>\n                    </Button>\n                  </TooltipTrigger>\n                  <TooltipContent side=\"bottom\">\n                    <p className=\"font-medium\">Ctrl/Cmd + Shift + E</p>\n                  </TooltipContent>\n                </Tooltip>\n              )}\n            </div>\n          </div>\n\n          {/* Error Display */}\n          {error && (\n            <motion.div\n              initial={{ opacity: 0, y: -10 }}\n              animate={{ opacity: 1, y: 0 }}\n              className=\"p-3 bg-red-50 dark:bg-red-950/30 border border-red-200 dark:border-red-800 rounded-lg flex items-center gap-3\"\n            >\n              <AlertCircle className=\"h-4 w-4 text-red-600 dark:text-red-400\" />\n              <div>\n                <p className=\"text-sm font-medium text-red-700 dark:text-red-300\">\n                  Evaluation Error\n                </p>\n                <p className=\"text-sm text-red-600 dark:text-red-400\">\n                  {error}\n                </p>\n              </div>\n            </motion.div>\n          )}\n\n          {/* Detailed View */}\n          <AnimatePresence mode=\"wait\">\n            {showDetails ? (\n              <motion.div\n                initial={{ opacity: 0 }}\n                animate={{ opacity: 1 }}\n                exit={{ opacity: 0 }}\n                className=\"flex-1 min-h-0\"\n              >\n                <Tabs\n                  value={activeTab}\n                  onValueChange={(v) => setActiveTab(v as any)}\n                  className=\"h-full flex flex-col\"\n                >\n                  <TabsList className=\"grid grid-cols-3 mb-4\">\n                    <TabsTrigger value=\"result\" className=\"text-sm\">\n                      <Activity className=\"h-4 w-4 mr-1\" />\n                      <span className=\"hidden sm:inline\">Result</span>\n                    </TabsTrigger>\n                    <TabsTrigger value=\"details\" className=\"text-sm\">\n                      <Code className=\"h-4 w-4 mr-1\" />\n                      <span className=\"hidden sm:inline\">Details</span>\n                    </TabsTrigger>\n                    <TabsTrigger value=\"data\" className=\"text-sm\">\n                      <FileJson className=\"h-4 w-4 mr-1\" />\n                      <span className=\"hidden sm:inline\">Data</span>\n                    </TabsTrigger>\n                  </TabsList>\n\n                  <div className=\"flex-1 min-h-0\">\n                    {/* Result Tab */}\n                    <TabsContent value=\"result\" className=\"h-full m-0\">\n                      {evaluationResult ? (\n                        <div className=\"space-y-4\">\n                          <div\n                            className={cn(\n                              \"p-6 rounded-xl border shadow-sm\",\n                              evaluationResult.isPassed\n                                ? \"bg-green-50 dark:bg-green-950/20 border-green-200 dark:border-green-800\"\n                                : \"bg-red-50 dark:bg-red-950/20 border-red-200 dark:border-red-800\",\n                            )}\n                          >\n                            <div className=\"flex items-center gap-3 mb-4\">\n                              {evaluationResult.isPassed ? (\n                                <CheckCircle2 className=\"h-6 w-6 text-green-600 dark:text-green-400\" />\n                              ) : (\n                                <XCircle className=\"h-6 w-6 text-red-600 dark:text-red-400\" />\n                              )}\n                              <div>\n                                <h3 className=\"text-xl font-semibold\">\n                                  Rule{\" \"}\n                                  {evaluationResult.isPassed\n                                    ? \"Passed\"\n                                    : \"Failed\"}\n                                </h3>\n                                <p className=\"text-sm text-muted-foreground\">\n                                  {evaluationResult.isPassed\n                                    ? \"All conditions were satisfied\"\n                                    : \"One or more conditions failed\"}\n                                </p>\n                              </div>\n                            </div>\n\n                            {evaluationResult.value && (\n                              <div>\n                                <Label className=\"text-sm font-medium mb-2 block\">\n                                  Result Value:\n                                </Label>\n                                <div className=\"p-3 bg-background rounded-lg border\">\n                                  <pre className=\"text-sm font-mono overflow-x-auto\">\n                                    {JSON.stringify(\n                                      evaluationResult.value,\n                                      null,\n                                      2,\n                                    )}\n                                  </pre>\n                                </div>\n                              </div>\n                            )}\n                          </div>\n                        </div>\n                      ) : (\n                        <div className=\"flex items-center justify-center h-full\">\n                          <div className=\"text-center space-y-3\">\n                            <Activity className=\"h-12 w-12 text-muted-foreground mx-auto\" />\n                            <div>\n                              <h3 className=\"font-medium\">No Results Yet</h3>\n                              <p className=\"text-sm text-muted-foreground\">\n                                {isLiveMode\n                                  ? \"Waiting for rule changes...\"\n                                  : 'Click \"Evaluate\" to test your rule'}\n                              </p>\n                            </div>\n                          </div>\n                        </div>\n                      )}\n                    </TabsContent>\n\n                    {/* Details Tab */}\n                    <TabsContent value=\"details\" className=\"h-full m-0\">\n                      <ScrollArea className=\"h-full\">\n                        <div className=\"space-y-2\">\n                          {evaluationDetails.length > 0 ? (\n                            evaluationDetails.map((detail) =>\n                              renderEvaluationDetails(detail),\n                            )\n                          ) : (\n                            <div className=\"flex items-center justify-center h-full\">\n                              <div className=\"text-center space-y-3\">\n                                <Code className=\"h-12 w-12 text-muted-foreground mx-auto\" />\n                                <div>\n                                  <h3 className=\"font-medium\">\n                                    No Details Available\n                                  </h3>\n                                  <p className=\"text-sm text-muted-foreground\">\n                                    Run an evaluation to see detailed breakdown\n                                  </p>\n                                </div>\n                              </div>\n                            </div>\n                          )}\n                        </div>\n                      </ScrollArea>\n                    </TabsContent>\n\n                    {/* Test Data Tab */}\n                    <TabsContent value=\"data\" className=\"h-full m-0\">\n                      <div className=\"space-y-4 h-full flex flex-col\">\n                        <div className=\"flex items-center justify-between\">\n                          <div>\n                            <Label className=\"text-base font-medium\">\n                              Test Data\n                            </Label>\n                            <p className=\"text-sm text-muted-foreground\">\n                              Edit the data used for evaluation\n                            </p>\n                          </div>\n                          <Button\n                            variant=\"outline\"\n                            size=\"sm\"\n                            onClick={() => setSampleData(defaultSampleData)}\n                          >\n                            Reset\n                          </Button>\n                        </div>\n                        <div className=\"flex-1 min-h-0\">\n                          <EditableJsonViewer\n                            rule={sampleData}\n                            onUpdate={setSampleData}\n                            className=\"h-full\"\n                            readOnly={false}\n                          />\n                        </div>\n                      </div>\n                    </TabsContent>\n                  </div>\n                </Tabs>\n              </motion.div>\n            ) : (\n              /* Compact Result View */\n              <motion.div\n                initial={{ opacity: 0 }}\n                animate={{ opacity: 1 }}\n                exit={{ opacity: 0 }}\n                className=\"flex-1 flex items-center justify-center\"\n              >\n                <div className=\"text-center space-y-4\">\n                  <div className=\"w-16 h-16 mx-auto rounded-full bg-muted/30 flex items-center justify-center\">\n                    <Activity className=\"h-8 w-8 text-muted-foreground\" />\n                  </div>\n                  <div>\n                    <h3 className=\"font-medium mb-2\">Ready to Evaluate</h3>\n                    <p className=\"text-sm text-muted-foreground mb-4\">\n                      {isLiveMode\n                        ? \"Live mode is active - changes will evaluate automatically\"\n                        : \"Click evaluate to test your rule, or enable live mode\"}\n                    </p>\n                    {!isLiveMode && (\n                      <Button\n                        onClick={runEvaluationOnce}\n                        disabled={isEvaluating}\n                      >\n                        <Play className=\"h-4 w-4 mr-2\" />\n                        Run Evaluation\n                      </Button>\n                    )}\n                  </div>\n                </div>\n              </motion.div>\n            )}\n          </AnimatePresence>\n        </CardContent>\n      </Card>\n    </TooltipProvider>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/rule-import-modal.tsx",
    "content": "import React, { useState, useRef } from \"react\";\nimport { Button } from \"./ui/button\";\nimport { Label } from \"./ui/label\";\nimport { Textarea } from \"./ui/textarea\";\nimport { Input } from \"./ui/input\";\nimport {\n  DialogTrigger,\n  DialogTitle,\n  DialogHeader,\n  DialogDescription,\n  DialogContent,\n  Dialog,\n} from \"./ui/dialog\";\nimport {\n  Upload,\n  Import,\n  FileText,\n  CheckCircle2,\n  AlertTriangle,\n} from \"lucide-react\";\nimport type { RuleType } from \"@usex/rule-engine\";\n\ninterface RuleImportModalProps {\n  onImport: (rule: RuleType) => void;\n  className?: string;\n}\n\nexport const RuleImportModal: React.FC<RuleImportModalProps> = ({\n  onImport,\n  className,\n}) => {\n  const [open, setOpen] = useState(false);\n  const [jsonText, setJsonText] = useState(\"\");\n  const [error, setError] = useState<string | null>(null);\n  const [success, setSuccess] = useState(false);\n  const fileInputRef = useRef<HTMLInputElement>(null);\n  const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n  // Auto-resize textarea\n  const adjustTextareaHeight = () => {\n    const textarea = textareaRef.current;\n    if (textarea) {\n      textarea.style.height = \"auto\";\n      textarea.style.height = `${Math.max(textarea.scrollHeight, 120)}px`;\n    }\n  };\n\n  const validateAndImportJson = (jsonString: string) => {\n    setError(null);\n    setSuccess(false);\n\n    if (!jsonString.trim()) {\n      setError(\"Please enter a JSON rule\");\n      return;\n    }\n\n    try {\n      const rule: RuleType = JSON.parse(jsonString);\n\n      // Basic validation\n      if (!rule.conditions) {\n        throw new Error(\"Rule must have a 'conditions' property\");\n      }\n\n      // Additional validation for the conditions structure\n      const condition = rule.conditions;\n      if (typeof condition !== \"object\" || condition === null) {\n        throw new Error(\"Conditions must be an object\");\n      }\n\n      const hasValidStructure =\n        (\"and\" in condition && Array.isArray(condition.and)) ||\n        (\"or\" in condition && Array.isArray(condition.or)) ||\n        (\"none\" in condition && Array.isArray(condition.none));\n\n      if (!hasValidStructure) {\n        throw new Error(\n          \"Conditions must have at least one of: 'and', 'or', or 'none' properties with array values\",\n        );\n      }\n\n      onImport(rule);\n      setSuccess(true);\n\n      // Clear after successful import and close modal\n      setTimeout(() => {\n        setJsonText(\"\");\n        setSuccess(false);\n        setError(null);\n        setOpen(false);\n        adjustTextareaHeight();\n      }, 1500);\n    } catch (err) {\n      setError(err instanceof Error ? err.message : \"Invalid JSON format\");\n    }\n  };\n\n  const handleTextareaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n    setJsonText(e.target.value);\n    setError(null);\n    setSuccess(false);\n    adjustTextareaHeight();\n  };\n\n  const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const file = e.target.files?.[0];\n    if (!file) return;\n\n    if (!file.name.endsWith(\".json\")) {\n      setError(\"Please select a JSON file (.json)\");\n      return;\n    }\n\n    const reader = new FileReader();\n    reader.onload = (event) => {\n      const content = event.target?.result as string;\n      setJsonText(content);\n      adjustTextareaHeight();\n      validateAndImportJson(content);\n    };\n\n    reader.onerror = () => {\n      setError(\"Failed to read file\");\n    };\n\n    reader.readAsText(file);\n\n    // Clear the input so the same file can be selected again\n    e.target.value = \"\";\n  };\n\n  const handleImportFromTextarea = () => {\n    validateAndImportJson(jsonText);\n  };\n\n  const handleClear = () => {\n    setJsonText(\"\");\n    setError(null);\n    setSuccess(false);\n    adjustTextareaHeight();\n  };\n\n  const handleOpenChange = (newOpen: boolean) => {\n    setOpen(newOpen);\n    if (!newOpen) {\n      // Reset state when closing\n      setJsonText(\"\");\n      setError(null);\n      setSuccess(false);\n    }\n  };\n\n  React.useEffect(() => {\n    if (open) {\n      adjustTextareaHeight();\n    }\n  }, [open]);\n\n  const sampleJson = `{\n  \"conditions\": {\n    \"and\": [\n      {\n        \"field\": \"user.age\",\n        \"operator\": \"greater_than\",\n        \"value\": 18\n      },\n      {\n        \"field\": \"user.status\",\n        \"operator\": \"equals\",\n        \"value\": \"active\"\n      }\n    ]\n  }\n}`;\n\n  return (\n    <Dialog open={open} onOpenChange={handleOpenChange}>\n      <DialogTrigger asChild>\n        <Button variant=\"outline\" className={className}>\n          <Import className=\"h-4 w-4 mr-2\" />\n          Import Rule JSON\n        </Button>\n      </DialogTrigger>\n      <DialogContent className=\"max-w-2xl max-h-[80vh] overflow-y-auto\">\n        <DialogHeader>\n          <DialogTitle className=\"flex items-center gap-2 text-gray-900 dark:text-white\">\n            <FileText className=\"h-5 w-5\" />\n            Import Rule JSON\n          </DialogTitle>\n          <DialogDescription className=\"text-gray-600 dark:text-gray-400\">\n            Import a rule by uploading a JSON file or pasting JSON directly\n          </DialogDescription>\n        </DialogHeader>\n\n        <div className=\"space-y-6 py-4\">\n          {/* File Upload Section */}\n          <div className=\"space-y-2\">\n            <Label\n              htmlFor=\"file-upload\"\n              className=\"text-gray-700 dark:text-gray-300\"\n            >\n              Upload JSON File\n            </Label>\n            <div className=\"flex items-center gap-2\">\n              <Input\n                ref={fileInputRef}\n                id=\"file-upload\"\n                type=\"file\"\n                accept=\".json\"\n                onChange={handleFileUpload}\n                className=\"hidden\"\n              />\n              <Button\n                type=\"button\"\n                variant=\"outline\"\n                onClick={() => fileInputRef.current?.click()}\n                className=\"flex items-center gap-2\"\n              >\n                <Upload className=\"h-4 w-4\" />\n                Choose JSON File\n              </Button>\n              <span className=\"text-sm text-gray-500 dark:text-gray-400\">\n                Select a .json file from your computer\n              </span>\n            </div>\n          </div>\n\n          {/* Text Area Section */}\n          <div className=\"space-y-2\">\n            <div className=\"flex items-center justify-between\">\n              <Label\n                htmlFor=\"json-textarea\"\n                className=\"text-gray-700 dark:text-gray-300\"\n              >\n                Or Paste JSON\n              </Label>\n              <Button\n                type=\"button\"\n                variant=\"ghost\"\n                size=\"sm\"\n                onClick={() => setJsonText(sampleJson)}\n                className=\"text-xs\"\n              >\n                Insert Sample\n              </Button>\n            </div>\n            <Textarea\n              ref={textareaRef}\n              id=\"json-textarea\"\n              value={jsonText}\n              onChange={handleTextareaChange}\n              placeholder=\"Paste your rule JSON here...\"\n              className=\"min-h-[120px] font-mono text-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 border-gray-300 dark:border-gray-600\"\n              style={{ resize: \"none\" }}\n            />\n            <div className=\"flex justify-between items-center\">\n              <div className=\"flex items-center gap-2\">\n                {error && (\n                  <div className=\"flex items-center gap-1 text-red-600 dark:text-red-400\">\n                    <AlertTriangle className=\"h-4 w-4\" />\n                    <span className=\"text-sm\">{error}</span>\n                  </div>\n                )}\n                {success && (\n                  <div className=\"flex items-center gap-1 text-green-600 dark:text-green-400\">\n                    <CheckCircle2 className=\"h-4 w-4\" />\n                    <span className=\"text-sm\">Rule imported successfully!</span>\n                  </div>\n                )}\n              </div>\n              <div className=\"flex gap-2\">\n                {jsonText && (\n                  <Button\n                    type=\"button\"\n                    variant=\"ghost\"\n                    size=\"sm\"\n                    onClick={handleClear}\n                  >\n                    Clear\n                  </Button>\n                )}\n                <Button\n                  type=\"button\"\n                  onClick={handleImportFromTextarea}\n                  disabled={!jsonText.trim()}\n                  size=\"sm\"\n                >\n                  Import JSON\n                </Button>\n              </div>\n            </div>\n          </div>\n\n          {/* Sample JSON Display */}\n          <div className=\"space-y-2\">\n            <Label className=\"text-gray-700 dark:text-gray-300\">\n              Expected JSON Format\n            </Label>\n            <pre className=\"bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100 p-3 rounded text-xs overflow-x-auto border border-gray-200 dark:border-gray-600\">\n              {sampleJson}\n            </pre>\n          </div>\n        </div>\n      </DialogContent>\n    </Dialog>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/rule-viewer.tsx",
    "content": "import React from \"react\";\nimport { CardTitle, CardHeader, CardContent, Card } from \"./ui/card\";\nimport { Button } from \"./ui/button\";\nimport { Copy, ChevronRight, ChevronDown, Check } from \"lucide-react\";\nimport { JsonViewer } from \"./JsonVisualizer\";\nimport type { RuleViewerProps } from \"../types\";\nimport { cn } from \"../lib/utils\";\n\nexport const RuleViewer: React.FC<RuleViewerProps> = ({\n  rule,\n  className,\n  collapsible = true,\n  defaultCollapsed = false,\n}) => {\n  const [collapsed, setCollapsed] = React.useState(defaultCollapsed);\n  const [copied, setCopied] = React.useState(false);\n\n  const handleCopy = async () => {\n    try {\n      const jsonString = JSON.stringify(rule, null, 2);\n      await navigator.clipboard.writeText(jsonString);\n      setCopied(true);\n      setTimeout(() => setCopied(false), 2000);\n    } catch (error) {\n      console.error(\"Failed to copy:\", error);\n    }\n  };\n\n  return (\n    <Card className={cn(\"overflow-hidden\", className)}>\n      <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n        <div className=\"flex items-center gap-2\">\n          {collapsible && (\n            <Button\n              type=\"button\"\n              variant=\"ghost\"\n              size=\"sm\"\n              onClick={() => setCollapsed(!collapsed)}\n              className=\"p-0 h-auto\"\n            >\n              {collapsed ? (\n                <ChevronRight className=\"h-4 w-4\" />\n              ) : (\n                <ChevronDown className=\"h-4 w-4\" />\n              )}\n            </Button>\n          )}\n          <CardTitle className=\"text-sm font-medium text-gray-900 dark:text-white\">\n            Rule JSON\n          </CardTitle>\n        </div>\n        <Button\n          type=\"button\"\n          variant=\"ghost\"\n          size=\"sm\"\n          onClick={handleCopy}\n          className=\"h-8 px-2\"\n        >\n          {copied ? (\n            <>\n              <Check className=\"h-4 w-4 mr-2 text-green-600\" />\n              Copied\n            </>\n          ) : (\n            <>\n              <Copy className=\"h-4 w-4 mr-2\" />\n              Copy\n            </>\n          )}\n        </Button>\n      </CardHeader>\n      {!collapsed && (\n        <CardContent>\n          <div className=\"rounded-lg bg-gray-50 dark:bg-background p-4 border border-gray-200 dark:border-gray-700\">\n            <JsonViewer\n              data={rule}\n              rootName=\"rule\"\n              defaultExpanded={true}\n              highlightLogicalOperators={true}\n              className=\"text-gray-900 dark:text-gray-100\"\n            />\n          </div>\n        </CardContent>\n      )}\n    </Card>\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/components/theme-provider.tsx",
    "content": "import React, { useState, useEffect, use, createContext } from \"react\";\n\ntype Theme = \"dark\" | \"light\" | \"system\";\n\ninterface ThemeProviderProps {\n  children: React.ReactNode;\n  defaultTheme?: Theme;\n  storageKey?: string;\n}\n\ninterface ThemeProviderState {\n  theme: Theme;\n  setTheme: (theme: Theme) => void;\n}\n\nconst initialState: ThemeProviderState = {\n  theme: \"system\",\n  setTheme: () => null,\n};\n\nconst ThemeProviderContext = createContext<ThemeProviderState>(initialState);\n\nexport function ThemeProvider({\n  children,\n  defaultTheme = \"system\",\n  storageKey = \"rule-builder-theme\",\n  ...props\n}: ThemeProviderProps) {\n  const [theme, setTheme] = useState<Theme>(\n    () => (localStorage.getItem(storageKey) as Theme) || defaultTheme,\n  );\n\n  useEffect(() => {\n    const root = window.document.documentElement;\n\n    root.classList.remove(\"light\", \"dark\");\n\n    if (theme === \"system\") {\n      const systemTheme = window.matchMedia(\"(prefers-color-scheme: dark)\")\n        .matches\n        ? \"dark\"\n        : \"light\";\n\n      root.classList.add(systemTheme);\n      return;\n    }\n\n    root.classList.add(theme);\n  }, [theme]);\n\n  const value = {\n    theme,\n    setTheme: (theme: Theme) => {\n      localStorage.setItem(storageKey, theme);\n      setTheme(theme);\n    },\n  };\n\n  return (\n    <ThemeProviderContext {...props} value={value}>\n      {children}\n    </ThemeProviderContext>\n  );\n}\n\nexport const useTheme = () => {\n  const context = use(ThemeProviderContext);\n\n  if (context === undefined)\n    throw new Error(\"useTheme must be used within a ThemeProvider\");\n\n  return context;\n};\n"
  },
  {
    "path": "packages/builder/src/components/theme-toggle.tsx",
    "content": "import { Sun, Moon } from \"lucide-react\";\nimport { useTheme } from \"./theme-provider\";\nimport { Button } from \"./ui/button\";\nimport {\n  DropdownMenuTrigger,\n  DropdownMenuItem,\n  DropdownMenuContent,\n  DropdownMenu,\n} from \"./ui/dropdown-menu\";\n\nexport function ThemeToggle() {\n  const { setTheme } = useTheme();\n\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger asChild>\n        <Button variant=\"outline\" size=\"icon\">\n          <Sun className=\"h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0\" />\n          <Moon className=\"absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100\" />\n          <span className=\"sr-only\">Toggle theme</span>\n        </Button>\n      </DropdownMenuTrigger>\n      <DropdownMenuContent align=\"end\">\n        <DropdownMenuItem onClick={() => setTheme(\"light\")}>\n          Light\n        </DropdownMenuItem>\n        <DropdownMenuItem onClick={() => setTheme(\"dark\")}>\n          Dark\n        </DropdownMenuItem>\n        <DropdownMenuItem onClick={() => setTheme(\"system\")}>\n          System\n        </DropdownMenuItem>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  );\n}\n"
  },
  {
    "path": "packages/builder/src/components/ui/alert.tsx",
    "content": "import * as React from \"react\";\nimport { cva } from \"class-variance-authority\";\nimport type { VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst alertVariants = cva(\n  \"relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg+div]:pl-7\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-background text-foreground\",\n        destructive:\n          \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  },\n);\n\nconst Alert = ({\n  ref,\n  className,\n  variant,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement> &\n  VariantProps<typeof alertVariants> & {\n    ref?: React.RefObject<HTMLDivElement | null>;\n  }) => (\n  <div\n    ref={ref}\n    role=\"alert\"\n    className={cn(alertVariants({ variant }), className)}\n    {...props}\n  />\n);\nAlert.displayName = \"Alert\";\n\nconst AlertTitle = ({\n  ref,\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLHeadingElement> & {\n  ref?: React.RefObject<HTMLParagraphElement | null>;\n}) => (\n  <h5\n    ref={ref}\n    className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n    {...props}\n  />\n);\nAlertTitle.displayName = \"AlertTitle\";\n\nconst AlertDescription = ({\n  ref,\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLParagraphElement> & {\n  ref?: React.RefObject<HTMLParagraphElement | null>;\n}) => (\n  <div\n    ref={ref}\n    className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n    {...props}\n  />\n);\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertDescription, AlertTitle };\n"
  },
  {
    "path": "packages/builder/src/components/ui/badge.tsx",
    "content": "import * as React from \"react\";\nimport { cva } from \"class-variance-authority\";\nimport type { VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst badgeVariants = cva(\n  \"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"border-transparent bg-primary text-primary-foreground hover:bg-primary/80\",\n        secondary:\n          \"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n        destructive:\n          \"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80\",\n        outline: \"text-foreground\",\n        or: \"border-transparent bg-blue-100 text-blue-900 dark:bg-blue-900 dark:text-blue-100\",\n        and: \"border-transparent bg-green-100 text-green-900 dark:bg-green-900 dark:text-green-100\",\n        none: \"border-transparent bg-red-100 text-red-900 dark:bg-red-900 dark:text-red-100\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  },\n);\n\nexport interface BadgeProps\n  extends React.HTMLAttributes<HTMLDivElement>,\n    VariantProps<typeof badgeVariants> {}\n\nfunction Badge({ className, variant, ...props }: BadgeProps) {\n  return (\n    <div className={cn(badgeVariants({ variant }), className)} {...props} />\n  );\n}\n\nexport { Badge, badgeVariants };\n"
  },
  {
    "path": "packages/builder/src/components/ui/button.tsx",
    "content": "import * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva } from \"class-variance-authority\";\nimport type { VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst buttonVariants = cva(\n  \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n        destructive:\n          \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n        outline:\n          \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n        secondary:\n          \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n        ghost: \"hover:bg-accent hover:text-accent-foreground\",\n        link: \"text-primary underline-offset-4 hover:underline\",\n      },\n      size: {\n        default: \"h-10 px-4 py-2\",\n        sm: \"h-9 rounded-md px-3\",\n        lg: \"h-11 rounded-md px-8\",\n        icon: \"h-10 w-10\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  },\n);\n\nexport interface ButtonProps\n  extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n    VariantProps<typeof buttonVariants> {\n  asChild?: boolean;\n}\n\nconst Button = ({\n  ref,\n  className,\n  variant,\n  size,\n  asChild = false,\n  ...props\n}: ButtonProps & { ref?: React.RefObject<HTMLButtonElement | null> }) => {\n  const Comp = asChild ? Slot : \"button\";\n  return (\n    <Comp\n      className={cn(buttonVariants({ variant, size, className }))}\n      ref={ref}\n      {...props}\n    />\n  );\n};\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n"
  },
  {
    "path": "packages/builder/src/components/ui/calendar.tsx",
    "content": "import * as React from \"react\";\nimport { DayPicker } from \"react-day-picker\";\nimport { cn } from \"../../lib/utils\";\n\nimport { buttonVariants } from \"./button\";\nimport \"react-day-picker/dist/style.css\";\n\nexport type CalendarProps = React.ComponentProps<typeof DayPicker>;\n\nfunction Calendar({\n  className,\n  classNames,\n  showOutsideDays = true,\n  ...props\n}: CalendarProps) {\n  return (\n    <DayPicker\n      showOutsideDays={showOutsideDays}\n      className={cn(\"p-3\", className)}\n      classNames={{\n        months: \"flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0\",\n        month: \"space-y-4\",\n        caption: \"flex justify-center pt-1 relative items-center\",\n        caption_label: \"text-sm font-medium\",\n        nav: \"space-x-1 flex items-center\",\n        nav_button: cn(\n          buttonVariants({ variant: \"outline\" }),\n          \"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100\",\n        ),\n        nav_button_previous: \"absolute left-1\",\n        nav_button_next: \"absolute right-1\",\n        table: \"w-full border-collapse space-y-1\",\n        head_row: \"flex\",\n        head_cell:\n          \"text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]\",\n        row: \"flex w-full mt-2\",\n        cell: \"h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20\",\n        day: cn(\n          buttonVariants({ variant: \"ghost\" }),\n          \"h-9 w-9 p-0 font-normal aria-selected:opacity-100\",\n        ),\n        day_range_end: \"day-range-end\",\n        day_selected:\n          \"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground\",\n        day_today: \"bg-accent text-accent-foreground\",\n        day_outside:\n          \"day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30\",\n        day_disabled: \"text-muted-foreground opacity-50\",\n        day_range_middle:\n          \"aria-selected:bg-accent aria-selected:text-accent-foreground\",\n        day_hidden: \"invisible\",\n        ...classNames,\n      }}\n      {...props}\n    />\n  );\n}\nCalendar.displayName = \"Calendar\";\n\nexport { Calendar };\n"
  },
  {
    "path": "packages/builder/src/components/ui/card.tsx",
    "content": "import * as React from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst Card = ({\n  className,\n  ref,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement> & {\n  ref?: React.Ref<HTMLDivElement>;\n}) => (\n  <div\n    ref={ref}\n    className={cn(\n      \"rounded-lg border bg-card text-card-foreground shadow-sm\",\n      className,\n    )}\n    {...props}\n  />\n);\nCard.displayName = \"Card\";\n\nconst CardHeader = ({\n  className,\n  ref,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement> & {\n  ref?: React.Ref<HTMLDivElement>;\n}) => (\n  <div\n    ref={ref}\n    className={cn(\"flex flex-col space-y-1.5 p-6\", className)}\n    {...props}\n  />\n);\nCardHeader.displayName = \"CardHeader\";\n\nconst CardTitle = ({\n  className,\n  ref,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement> & {\n  ref?: React.Ref<HTMLDivElement>;\n}) => (\n  <div\n    ref={ref}\n    className={cn(\n      \"text-2xl font-semibold leading-none tracking-tight\",\n      className,\n    )}\n    {...props}\n  />\n);\nCardTitle.displayName = \"CardTitle\";\n\nconst CardDescription = ({\n  className,\n  ref,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement> & {\n  ref?: React.Ref<HTMLDivElement>;\n}) => (\n  <div\n    ref={ref}\n    className={cn(\"text-sm text-muted-foreground\", className)}\n    {...props}\n  />\n);\nCardDescription.displayName = \"CardDescription\";\n\nconst CardContent = ({\n  className,\n  ref,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement> & {\n  ref?: React.Ref<HTMLDivElement>;\n}) => <div ref={ref} className={cn(\"p-6 pt-0\", className)} {...props} />;\nCardContent.displayName = \"CardContent\";\n\nconst CardFooter = ({\n  className,\n  ref,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement> & {\n  ref?: React.Ref<HTMLDivElement>;\n}) => (\n  <div\n    ref={ref}\n    className={cn(\"flex items-center p-6 pt-0\", className)}\n    {...props}\n  />\n);\nCardFooter.displayName = \"CardFooter\";\n\nexport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n};\n"
  },
  {
    "path": "packages/builder/src/components/ui/collapsible.tsx",
    "content": "import * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\n\nconst Collapsible = CollapsiblePrimitive.Root;\n\nconst CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;\n\nconst CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;\n\nexport { Collapsible, CollapsibleContent, CollapsibleTrigger };\n"
  },
  {
    "path": "packages/builder/src/components/ui/command.tsx",
    "content": "import * as React from \"react\";\nimport type { DialogProps } from \"@radix-ui/react-dialog\";\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport { Search } from \"lucide-react\";\n\nimport { cn } from \"../../lib/utils\";\nimport { DialogContent, Dialog } from \"./dialog\";\n\nconst Command = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof CommandPrimitive> & {\n  ref?: React.RefObject<React.ElementRef<typeof CommandPrimitive> | null>;\n}) => (\n  <CommandPrimitive\n    ref={ref}\n    className={cn(\n      \"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground\",\n      className,\n    )}\n    {...props}\n  />\n);\nCommand.displayName = CommandPrimitive.displayName;\n\ninterface CommandDialogProps extends DialogProps {}\n\nconst CommandDialog = ({ children, ...props }: CommandDialogProps) => {\n  return (\n    <Dialog {...props}>\n      <DialogContent className=\"overflow-hidden p-0 shadow-lg\">\n        <Command className=\"[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5\">\n          {children}\n        </Command>\n      </DialogContent>\n    </Dialog>\n  );\n};\n\nconst CommandInput = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input> & {\n  ref?: React.RefObject<React.ElementRef<typeof CommandPrimitive.Input> | null>;\n}) => (\n  <div className=\"flex items-center border-b px-3\" cmdk-input-wrapper=\"\">\n    <Search className=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n    <CommandPrimitive.Input\n      ref={ref}\n      className={cn(\n        \"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n        className,\n      )}\n      {...props}\n    />\n  </div>\n);\n\nCommandInput.displayName = CommandPrimitive.Input.displayName;\n\nconst CommandList = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof CommandPrimitive.List> & {\n  ref?: React.RefObject<React.ElementRef<typeof CommandPrimitive.List> | null>;\n}) => (\n  <CommandPrimitive.List\n    ref={ref}\n    className={cn(\"max-h-[300px] overflow-y-auto overflow-x-hidden\", className)}\n    {...props}\n  />\n);\n\nCommandList.displayName = CommandPrimitive.List.displayName;\n\nconst CommandEmpty = ({\n  ref,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty> & {\n  ref?: React.RefObject<React.ElementRef<typeof CommandPrimitive.Empty> | null>;\n}) => (\n  <CommandPrimitive.Empty\n    ref={ref}\n    className=\"py-6 text-center text-sm\"\n    {...props}\n  />\n);\n\nCommandEmpty.displayName = CommandPrimitive.Empty.displayName;\n\nconst CommandGroup = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group> & {\n  ref?: React.RefObject<React.ElementRef<typeof CommandPrimitive.Group> | null>;\n}) => (\n  <CommandPrimitive.Group\n    ref={ref}\n    className={cn(\n      \"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground\",\n      className,\n    )}\n    {...props}\n  />\n);\n\nCommandGroup.displayName = CommandPrimitive.Group.displayName;\n\nconst CommandSeparator = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof CommandPrimitive.Separator\n  > | null>;\n}) => (\n  <CommandPrimitive.Separator\n    ref={ref}\n    className={cn(\"-mx-1 h-px bg-border\", className)}\n    {...props}\n  />\n);\nCommandSeparator.displayName = CommandPrimitive.Separator.displayName;\n\nconst CommandItem = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item> & {\n  ref?: React.RefObject<React.ElementRef<typeof CommandPrimitive.Item> | null>;\n}) => (\n  <CommandPrimitive.Item\n    ref={ref}\n    className={cn(\n      \"relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50\",\n      className,\n    )}\n    {...props}\n  />\n);\n\nCommandItem.displayName = CommandPrimitive.Item.displayName;\n\nconst CommandShortcut = ({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n  return (\n    <span\n      className={cn(\n        \"ml-auto text-xs tracking-widest text-muted-foreground\",\n        className,\n      )}\n      {...props}\n    />\n  );\n};\nCommandShortcut.displayName = \"CommandShortcut\";\n\nexport {\n  Command,\n  CommandDialog,\n  CommandEmpty,\n  CommandGroup,\n  CommandInput,\n  CommandItem,\n  CommandList,\n  CommandSeparator,\n  CommandShortcut,\n};\n"
  },
  {
    "path": "packages/builder/src/components/ui/dialog.tsx",
    "content": "import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst Dialog = DialogPrimitive.Root;\n\nconst DialogTrigger = DialogPrimitive.Trigger;\n\nconst DialogPortal = DialogPrimitive.Portal;\n\nconst DialogClose = DialogPrimitive.Close;\n\nconst DialogOverlay = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DialogPrimitive.Overlay\n  > | null>;\n}) => (\n  <DialogPrimitive.Overlay\n    ref={ref}\n    className={cn(\n      \"fixed inset-0 z-50 bg-black/80  data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n      className,\n    )}\n    {...props}\n  />\n);\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\nconst DialogContent = ({\n  ref,\n  className,\n  children,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DialogPrimitive.Content\n  > | null>;\n}) => (\n  <DialogPortal>\n    <DialogOverlay />\n    <DialogPrimitive.Content\n      ref={ref}\n      className={cn(\n        \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-half data-[state=closed]:slide-out-to-top-48 data-[state=open]:slide-in-from-left-half data-[state=open]:slide-in-from-top-48 sm:rounded-lg\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n      <DialogPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground\">\n        <X className=\"h-4 w-4\" />\n        <span className=\"sr-only\">Close</span>\n      </DialogPrimitive.Close>\n    </DialogPrimitive.Content>\n  </DialogPortal>\n);\nDialogContent.displayName = DialogPrimitive.Content.displayName;\n\nconst DialogHeader = ({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n  <div\n    className={cn(\n      \"flex flex-col space-y-1.5 text-center sm:text-left\",\n      className,\n    )}\n    {...props}\n  />\n);\nDialogHeader.displayName = \"DialogHeader\";\n\nconst DialogFooter = ({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n  <div\n    className={cn(\n      \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n      className,\n    )}\n    {...props}\n  />\n);\nDialogFooter.displayName = \"DialogFooter\";\n\nconst DialogTitle = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> & {\n  ref?: React.RefObject<React.ElementRef<typeof DialogPrimitive.Title> | null>;\n}) => (\n  <DialogPrimitive.Title\n    ref={ref}\n    className={cn(\n      \"text-lg font-semibold leading-none tracking-tight\",\n      className,\n    )}\n    {...props}\n  />\n);\nDialogTitle.displayName = DialogPrimitive.Title.displayName;\n\nconst DialogDescription = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DialogPrimitive.Description\n  > | null>;\n}) => (\n  <DialogPrimitive.Description\n    ref={ref}\n    className={cn(\"text-sm text-muted-foreground\", className)}\n    {...props}\n  />\n);\nDialogDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n  Dialog,\n  DialogClose,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogOverlay,\n  DialogPortal,\n  DialogTitle,\n  DialogTrigger,\n};\n"
  },
  {
    "path": "packages/builder/src/components/ui/dropdown-menu.tsx",
    "content": "import * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Circle, ChevronRight, Check } from \"lucide-react\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst DropdownMenu = DropdownMenuPrimitive.Root;\n\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\nconst DropdownMenuSub = DropdownMenuPrimitive.Sub;\n\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nconst DropdownMenuSubTrigger = ({\n  ref,\n  className,\n  inset,\n  children,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {\n  inset?: boolean;\n} & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DropdownMenuPrimitive.SubTrigger\n  > | null>;\n}) => (\n  <DropdownMenuPrimitive.SubTrigger\n    ref={ref}\n    className={cn(\n      \"flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n      inset && \"pl-8\",\n      className,\n    )}\n    {...props}\n  >\n    {children}\n    <ChevronRight className=\"ml-auto\" />\n  </DropdownMenuPrimitive.SubTrigger>\n);\nDropdownMenuSubTrigger.displayName =\n  DropdownMenuPrimitive.SubTrigger.displayName;\n\nconst DropdownMenuSubContent = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DropdownMenuPrimitive.SubContent\n  > | null>;\n}) => (\n  <DropdownMenuPrimitive.SubContent\n    ref={ref}\n    className={cn(\n      \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n      className,\n    )}\n    {...props}\n  />\n);\nDropdownMenuSubContent.displayName =\n  DropdownMenuPrimitive.SubContent.displayName;\n\nconst DropdownMenuContent = ({\n  ref,\n  className,\n  sideOffset = 4,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DropdownMenuPrimitive.Content\n  > | null>;\n}) => (\n  <DropdownMenuPrimitive.Portal>\n    <DropdownMenuPrimitive.Content\n      ref={ref}\n      sideOffset={sideOffset}\n      className={cn(\n        \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n        className,\n      )}\n      {...props}\n    />\n  </DropdownMenuPrimitive.Portal>\n);\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\nconst DropdownMenuItem = ({\n  ref,\n  className,\n  inset,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n  inset?: boolean;\n} & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DropdownMenuPrimitive.Item\n  > | null>;\n}) => (\n  <DropdownMenuPrimitive.Item\n    ref={ref}\n    className={cn(\n      \"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n      inset && \"pl-8\",\n      className,\n    )}\n    {...props}\n  />\n);\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n\nconst DropdownMenuCheckboxItem = ({\n  ref,\n  className,\n  children,\n  checked,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DropdownMenuPrimitive.CheckboxItem\n  > | null>;\n}) => (\n  <DropdownMenuPrimitive.CheckboxItem\n    ref={ref}\n    className={cn(\n      \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n      className,\n    )}\n    checked={checked}\n    {...props}\n  >\n    <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n      <DropdownMenuPrimitive.ItemIndicator>\n        <Check className=\"h-4 w-4\" />\n      </DropdownMenuPrimitive.ItemIndicator>\n    </span>\n    {children}\n  </DropdownMenuPrimitive.CheckboxItem>\n);\nDropdownMenuCheckboxItem.displayName =\n  DropdownMenuPrimitive.CheckboxItem.displayName;\n\nconst DropdownMenuRadioItem = ({\n  ref,\n  className,\n  children,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DropdownMenuPrimitive.RadioItem\n  > | null>;\n}) => (\n  <DropdownMenuPrimitive.RadioItem\n    ref={ref}\n    className={cn(\n      \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n      className,\n    )}\n    {...props}\n  >\n    <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n      <DropdownMenuPrimitive.ItemIndicator>\n        <Circle className=\"h-2 w-2 fill-current\" />\n      </DropdownMenuPrimitive.ItemIndicator>\n    </span>\n    {children}\n  </DropdownMenuPrimitive.RadioItem>\n);\nDropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;\n\nconst DropdownMenuLabel = ({\n  ref,\n  className,\n  inset,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n  inset?: boolean;\n} & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DropdownMenuPrimitive.Label\n  > | null>;\n}) => (\n  <DropdownMenuPrimitive.Label\n    ref={ref}\n    className={cn(\n      \"px-2 py-1.5 text-sm font-semibold\",\n      inset && \"pl-8\",\n      className,\n    )}\n    {...props}\n  />\n);\nDropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;\n\nconst DropdownMenuSeparator = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DropdownMenuPrimitive.Separator\n  > | null>;\n}) => (\n  <DropdownMenuPrimitive.Separator\n    ref={ref}\n    className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n    {...props}\n  />\n);\nDropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;\n\nconst DropdownMenuShortcut = ({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n  return (\n    <span\n      className={cn(\"ml-auto text-xs tracking-widest opacity-60\", className)}\n      {...props}\n    />\n  );\n};\nDropdownMenuShortcut.displayName = \"DropdownMenuShortcut\";\n\nexport {\n  DropdownMenu,\n  DropdownMenuCheckboxItem,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuPortal,\n  DropdownMenuRadioGroup,\n  DropdownMenuRadioItem,\n  DropdownMenuSeparator,\n  DropdownMenuShortcut,\n  DropdownMenuSub,\n  DropdownMenuSubContent,\n  DropdownMenuSubTrigger,\n  DropdownMenuTrigger,\n};\n"
  },
  {
    "path": "packages/builder/src/components/ui/input.tsx",
    "content": "import * as React from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst Input = ({\n  ref,\n  className,\n  type,\n  ...props\n}: React.ComponentProps<\"input\"> & {\n  ref?: React.RefObject<HTMLInputElement | null>;\n}) => {\n  return (\n    <input\n      type={type}\n      className={cn(\n        \"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n        className,\n      )}\n      ref={ref}\n      {...props}\n    />\n  );\n};\nInput.displayName = \"Input\";\n\nexport { Input };\n"
  },
  {
    "path": "packages/builder/src/components/ui/label.tsx",
    "content": "import * as React from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { cva } from \"class-variance-authority\";\nimport type { VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst labelVariants = cva(\n  \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n);\n\nconst Label = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &\n  VariantProps<typeof labelVariants> & {\n    ref?: React.RefObject<React.ElementRef<typeof LabelPrimitive.Root> | null>;\n  }) => (\n  <LabelPrimitive.Root\n    ref={ref}\n    className={cn(labelVariants(), className)}\n    {...props}\n  />\n);\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n"
  },
  {
    "path": "packages/builder/src/components/ui/popover.tsx",
    "content": "import * as React from \"react\";\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst Popover = PopoverPrimitive.Root;\n\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\nconst PopoverContent = ({\n  ref,\n  className,\n  align = \"center\",\n  sideOffset = 4,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof PopoverPrimitive.Content\n  > | null>;\n}) => (\n  <PopoverPrimitive.Portal>\n    <PopoverPrimitive.Content\n      ref={ref}\n      align={align}\n      sideOffset={sideOffset}\n      className={cn(\n        \"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n        className,\n      )}\n      {...props}\n    />\n  </PopoverPrimitive.Portal>\n);\nPopoverContent.displayName = PopoverPrimitive.Content.displayName;\n\nexport { Popover, PopoverContent, PopoverTrigger };\n"
  },
  {
    "path": "packages/builder/src/components/ui/scroll-area.tsx",
    "content": "import * as React from \"react\";\nimport * as ScrollAreaPrimitive from \"@radix-ui/react-scroll-area\";\nimport { cn } from \"../../lib/utils\";\n\nconst ScrollBar = ({\n  ref,\n  className,\n  orientation = \"vertical\",\n  ...props\n}: React.ComponentPropsWithoutRef<\n  typeof ScrollAreaPrimitive.ScrollAreaScrollbar\n> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof ScrollAreaPrimitive.ScrollAreaScrollbar\n  > | null>;\n}) => (\n  <ScrollAreaPrimitive.ScrollAreaScrollbar\n    ref={ref}\n    orientation={orientation}\n    className={cn(\n      \"flex touch-none select-none transition-colors\",\n      orientation === \"vertical\" &&\n        \"h-full w-2.5 border-l border-l-transparent p-[1px]\",\n      orientation === \"horizontal\" &&\n        \"h-2.5 w-full border-t border-t-transparent p-[1px]\",\n      className,\n    )}\n    {...props}\n  >\n    <ScrollAreaPrimitive.ScrollAreaThumb className=\"relative flex-1 rounded-full bg-border\" />\n  </ScrollAreaPrimitive.ScrollAreaScrollbar>\n);\nScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;\n\nconst ScrollArea = ({\n  ref,\n  className,\n  children,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof ScrollAreaPrimitive.Root\n  > | null>;\n}) => (\n  <ScrollAreaPrimitive.Root\n    ref={ref}\n    className={cn(\"relative overflow-hidden\", className)}\n    {...props}\n  >\n    <ScrollAreaPrimitive.Viewport className=\"h-full w-full rounded-[inherit]\">\n      {children}\n    </ScrollAreaPrimitive.Viewport>\n    <ScrollBar />\n    <ScrollAreaPrimitive.Corner />\n  </ScrollAreaPrimitive.Root>\n);\nScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;\n\nexport { ScrollArea, ScrollBar };\n"
  },
  {
    "path": "packages/builder/src/components/ui/select.tsx",
    "content": "import * as React from \"react\";\nimport * as SelectPrimitive from \"@radix-ui/react-select\";\nimport { ChevronUp, ChevronDown, Check } from \"lucide-react\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst Select = SelectPrimitive.Root;\n\nconst SelectGroup = SelectPrimitive.Group;\n\nconst SelectValue = SelectPrimitive.Value;\n\nconst SelectTrigger = ({\n  ref,\n  className,\n  children,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof SelectPrimitive.Trigger\n  > | null>;\n}) => (\n  <SelectPrimitive.Trigger\n    ref={ref}\n    className={cn(\n      \"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1\",\n      className,\n    )}\n    {...props}\n  >\n    {children}\n    <SelectPrimitive.Icon asChild>\n      <ChevronDown className=\"h-4 w-4 opacity-50\" />\n    </SelectPrimitive.Icon>\n  </SelectPrimitive.Trigger>\n);\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName;\n\nconst SelectScrollUpButton = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof SelectPrimitive.ScrollUpButton\n  > | null>;\n}) => (\n  <SelectPrimitive.ScrollUpButton\n    ref={ref}\n    className={cn(\n      \"flex cursor-default items-center justify-center py-1\",\n      className,\n    )}\n    {...props}\n  >\n    <ChevronUp className=\"h-4 w-4\" />\n  </SelectPrimitive.ScrollUpButton>\n);\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;\n\nconst SelectScrollDownButton = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof SelectPrimitive.ScrollDownButton\n  > | null>;\n}) => (\n  <SelectPrimitive.ScrollDownButton\n    ref={ref}\n    className={cn(\n      \"flex cursor-default items-center justify-center py-1\",\n      className,\n    )}\n    {...props}\n  >\n    <ChevronDown className=\"h-4 w-4\" />\n  </SelectPrimitive.ScrollDownButton>\n);\nSelectScrollDownButton.displayName =\n  SelectPrimitive.ScrollDownButton.displayName;\n\nconst SelectContent = ({\n  ref,\n  className,\n  children,\n  position = \"popper\",\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof SelectPrimitive.Content\n  > | null>;\n}) => (\n  <SelectPrimitive.Portal>\n    <SelectPrimitive.Content\n      ref={ref}\n      className={cn(\n        \"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n        position === \"popper\" &&\n          \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n        className,\n      )}\n      position={position}\n      {...props}\n    >\n      <SelectScrollUpButton />\n      <SelectPrimitive.Viewport\n        className={cn(\n          \"p-1\",\n          position === \"popper\" &&\n            \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]\",\n        )}\n      >\n        {children}\n      </SelectPrimitive.Viewport>\n      <SelectScrollDownButton />\n    </SelectPrimitive.Content>\n  </SelectPrimitive.Portal>\n);\nSelectContent.displayName = SelectPrimitive.Content.displayName;\n\nconst SelectLabel = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label> & {\n  ref?: React.RefObject<React.ElementRef<typeof SelectPrimitive.Label> | null>;\n}) => (\n  <SelectPrimitive.Label\n    ref={ref}\n    className={cn(\"py-1.5 pl-8 pr-2 text-sm font-semibold\", className)}\n    {...props}\n  />\n);\nSelectLabel.displayName = SelectPrimitive.Label.displayName;\n\nconst SelectItem = ({\n  ref,\n  className,\n  children,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item> & {\n  ref?: React.RefObject<React.ElementRef<typeof SelectPrimitive.Item> | null>;\n}) => (\n  <SelectPrimitive.Item\n    ref={ref}\n    className={cn(\n      \"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n      className,\n    )}\n    {...props}\n  >\n    <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n      <SelectPrimitive.ItemIndicator>\n        <Check className=\"h-4 w-4\" />\n      </SelectPrimitive.ItemIndicator>\n    </span>\n\n    <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n  </SelectPrimitive.Item>\n);\nSelectItem.displayName = SelectPrimitive.Item.displayName;\n\nconst SelectSeparator = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof SelectPrimitive.Separator\n  > | null>;\n}) => (\n  <SelectPrimitive.Separator\n    ref={ref}\n    className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n    {...props}\n  />\n);\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName;\n\nexport {\n  Select,\n  SelectContent,\n  SelectGroup,\n  SelectItem,\n  SelectLabel,\n  SelectScrollDownButton,\n  SelectScrollUpButton,\n  SelectSeparator,\n  SelectTrigger,\n  SelectValue,\n};\n"
  },
  {
    "path": "packages/builder/src/components/ui/separator.tsx",
    "content": "import * as React from \"react\";\nimport * as SeparatorPrimitive from \"@radix-ui/react-separator\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst Separator = ({\n  ref,\n  className,\n  orientation = \"horizontal\",\n  decorative = true,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof SeparatorPrimitive.Root\n  > | null>;\n}) => (\n  <SeparatorPrimitive.Root\n    ref={ref}\n    decorative={decorative}\n    orientation={orientation}\n    className={cn(\n      \"shrink-0 bg-border\",\n      orientation === \"horizontal\" ? \"h-[1px] w-full\" : \"h-full w-[1px]\",\n      className,\n    )}\n    {...props}\n  />\n);\nSeparator.displayName = SeparatorPrimitive.Root.displayName;\n\nexport { Separator };\n"
  },
  {
    "path": "packages/builder/src/components/ui/sheet.tsx",
    "content": "import * as React from \"react\";\nimport * as SheetPrimitive from \"@radix-ui/react-dialog\";\nimport { cva } from \"class-variance-authority\";\nimport type { VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst Sheet = SheetPrimitive.Root;\n\nconst SheetTrigger = SheetPrimitive.Trigger;\n\nconst SheetClose = SheetPrimitive.Close;\n\nconst SheetPortal = SheetPrimitive.Portal;\n\nconst SheetOverlay = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay> & {\n  ref?: React.RefObject<React.ElementRef<typeof SheetPrimitive.Overlay> | null>;\n}) => (\n  <SheetPrimitive.Overlay\n    className={cn(\n      \"fixed inset-0 z-50 bg-black/80  data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n      className,\n    )}\n    {...props}\n    ref={ref}\n  />\n);\nSheetOverlay.displayName = SheetPrimitive.Overlay.displayName;\n\nconst sheetVariants = cva(\n  \"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500\",\n  {\n    variants: {\n      side: {\n        top: \"inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n        bottom:\n          \"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n        left: \"inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm\",\n        right:\n          \"inset-y-0 right-0 h-full w-3/4  border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm\",\n      },\n    },\n    defaultVariants: {\n      side: \"right\",\n    },\n  },\n);\n\ninterface SheetContentProps\n  extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,\n    VariantProps<typeof sheetVariants> {}\n\nconst SheetContent = ({\n  ref,\n  side = \"right\",\n  className,\n  children,\n  ...props\n}: SheetContentProps & {\n  ref?: React.RefObject<React.ElementRef<typeof SheetPrimitive.Content> | null>;\n}) => (\n  <SheetPortal>\n    <SheetOverlay />\n    <SheetPrimitive.Content\n      ref={ref}\n      className={cn(sheetVariants({ side }), className)}\n      {...props}\n    >\n      {children}\n      <SheetPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary\">\n        <X className=\"h-4 w-4\" />\n        <span className=\"sr-only\">Close</span>\n      </SheetPrimitive.Close>\n    </SheetPrimitive.Content>\n  </SheetPortal>\n);\nSheetContent.displayName = SheetPrimitive.Content.displayName;\n\nconst SheetHeader = ({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n  <div\n    className={cn(\n      \"flex flex-col space-y-2 text-center sm:text-left\",\n      className,\n    )}\n    {...props}\n  />\n);\nSheetHeader.displayName = \"SheetHeader\";\n\nconst SheetFooter = ({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n  <div\n    className={cn(\n      \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n      className,\n    )}\n    {...props}\n  />\n);\nSheetFooter.displayName = \"SheetFooter\";\n\nconst SheetTitle = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title> & {\n  ref?: React.RefObject<React.ElementRef<typeof SheetPrimitive.Title> | null>;\n}) => (\n  <SheetPrimitive.Title\n    ref={ref}\n    className={cn(\"text-lg font-semibold text-foreground\", className)}\n    {...props}\n  />\n);\nSheetTitle.displayName = SheetPrimitive.Title.displayName;\n\nconst SheetDescription = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof SheetPrimitive.Description\n  > | null>;\n}) => (\n  <SheetPrimitive.Description\n    ref={ref}\n    className={cn(\"text-sm text-muted-foreground\", className)}\n    {...props}\n  />\n);\nSheetDescription.displayName = SheetPrimitive.Description.displayName;\n\nexport {\n  Sheet,\n  SheetClose,\n  SheetContent,\n  SheetDescription,\n  SheetFooter,\n  SheetHeader,\n  SheetOverlay,\n  SheetPortal,\n  SheetTitle,\n  SheetTrigger,\n};\n"
  },
  {
    "path": "packages/builder/src/components/ui/slider.tsx",
    "content": "import * as React from \"react\";\nimport * as SliderPrimitive from \"@radix-ui/react-slider\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst Slider = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> & {\n  ref?: React.RefObject<React.ElementRef<typeof SliderPrimitive.Root> | null>;\n}) => (\n  <SliderPrimitive.Root\n    ref={ref}\n    className={cn(\n      \"relative flex w-full touch-none select-none items-center\",\n      className,\n    )}\n    {...props}\n  >\n    <SliderPrimitive.Track className=\"relative h-2 w-full grow overflow-hidden rounded-full bg-secondary\">\n      <SliderPrimitive.Range className=\"absolute h-full bg-primary\" />\n    </SliderPrimitive.Track>\n    <SliderPrimitive.Thumb className=\"block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\" />\n  </SliderPrimitive.Root>\n);\nSlider.displayName = SliderPrimitive.Root.displayName;\n\nexport { Slider };\n"
  },
  {
    "path": "packages/builder/src/components/ui/sonner.tsx",
    "content": "import { useTheme } from \"../../hooks/use-theme\";\nimport { Toaster as Sonner } from \"sonner\";\n\ntype ToasterProps = React.ComponentProps<typeof Sonner>;\n\nconst Toaster = ({ ...props }: ToasterProps) => {\n  const { resolvedTheme } = useTheme();\n\n  return (\n    <Sonner\n      theme={resolvedTheme as ToasterProps[\"theme\"]}\n      className=\"toaster group\"\n      toastOptions={{\n        classNames: {\n          toast:\n            \"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg\",\n          description: \"group-[.toast]:text-muted-foreground\",\n          actionButton:\n            \"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground\",\n          cancelButton:\n            \"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground\",\n        },\n      }}\n      {...props}\n    />\n  );\n};\n\nexport { Toaster };\n"
  },
  {
    "path": "packages/builder/src/components/ui/switch.tsx",
    "content": "import * as React from \"react\";\nimport * as SwitchPrimitives from \"@radix-ui/react-switch\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst Switch = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> & {\n  ref?: React.RefObject<React.ElementRef<typeof SwitchPrimitives.Root> | null>;\n}) => (\n  <SwitchPrimitives.Root\n    className={cn(\n      \"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input\",\n      className,\n    )}\n    {...props}\n    ref={ref}\n  >\n    <SwitchPrimitives.Thumb\n      className={cn(\n        \"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0\",\n      )}\n    />\n  </SwitchPrimitives.Root>\n);\nSwitch.displayName = SwitchPrimitives.Root.displayName;\n\nexport { Switch };\n"
  },
  {
    "path": "packages/builder/src/components/ui/tabs.tsx",
    "content": "import * as React from \"react\";\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst Tabs = TabsPrimitive.Root;\n\nconst TabsList = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> & {\n  ref?: React.RefObject<React.ElementRef<typeof TabsPrimitive.List> | null>;\n}) => (\n  <TabsPrimitive.List\n    ref={ref}\n    className={cn(\n      \"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground\",\n      className,\n    )}\n    {...props}\n  />\n);\nTabsList.displayName = TabsPrimitive.List.displayName;\n\nconst TabsTrigger = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger> & {\n  ref?: React.RefObject<React.ElementRef<typeof TabsPrimitive.Trigger> | null>;\n}) => (\n  <TabsPrimitive.Trigger\n    ref={ref}\n    className={cn(\n      \"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm\",\n      className,\n    )}\n    {...props}\n  />\n);\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName;\n\nconst TabsContent = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content> & {\n  ref?: React.RefObject<React.ElementRef<typeof TabsPrimitive.Content> | null>;\n}) => (\n  <TabsPrimitive.Content\n    ref={ref}\n    className={cn(\n      \"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n      className,\n    )}\n    {...props}\n  />\n);\nTabsContent.displayName = TabsPrimitive.Content.displayName;\n\nexport { Tabs, TabsContent, TabsList, TabsTrigger };\n"
  },
  {
    "path": "packages/builder/src/components/ui/textarea.tsx",
    "content": "import * as React from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nexport interface TextareaProps\n  extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}\n\nconst Textarea = ({\n  ref,\n  className,\n  ...props\n}: TextareaProps & { ref?: React.RefObject<HTMLTextAreaElement | null> }) => {\n  return (\n    <textarea\n      className={cn(\n        \"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50\",\n        className,\n      )}\n      ref={ref}\n      {...props}\n    />\n  );\n};\nTextarea.displayName = \"Textarea\";\n\nexport { Textarea };\n"
  },
  {
    "path": "packages/builder/src/components/ui/tooltip.tsx",
    "content": "import * as React from \"react\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst TooltipProvider = TooltipPrimitive.Provider;\n\nconst Tooltip = TooltipPrimitive.Root;\n\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = ({\n  ref,\n  className,\n  sideOffset = 4,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof TooltipPrimitive.Content\n  > | null>;\n}) => (\n  <TooltipPrimitive.Content\n    ref={ref}\n    sideOffset={sideOffset}\n    className={cn(\n      \"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n      className,\n    )}\n    {...props}\n  />\n);\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };\n"
  },
  {
    "path": "packages/builder/src/components/ui/zoom-dialog.tsx",
    "content": "import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst ZoomDialog = DialogPrimitive.Root;\n\nconst ZoomDialogTrigger = DialogPrimitive.Trigger;\n\nconst ZoomDialogPortal = DialogPrimitive.Portal;\n\nconst ZoomDialogClose = DialogPrimitive.Close;\n\nconst ZoomDialogOverlay = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DialogPrimitive.Overlay\n  > | null>;\n}) => (\n  <DialogPrimitive.Overlay\n    ref={ref}\n    className={cn(\n      \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n      className,\n    )}\n    {...props}\n  />\n);\nZoomDialogOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\nconst ZoomDialogContent = ({\n  ref,\n  className,\n  children,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DialogPrimitive.Content\n  > | null>;\n}) => (\n  <ZoomDialogPortal>\n    <ZoomDialogOverlay />\n    <DialogPrimitive.Content\n      ref={ref}\n      className={cn(\n        \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-300 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-90 data-[state=open]:zoom-in-90 sm:rounded-lg\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n      <DialogPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground\">\n        <X className=\"h-4 w-4\" />\n        <span className=\"sr-only\">Close</span>\n      </DialogPrimitive.Close>\n    </DialogPrimitive.Content>\n  </ZoomDialogPortal>\n);\nZoomDialogContent.displayName = DialogPrimitive.Content.displayName;\n\nconst ZoomDialogHeader = ({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n  <div\n    className={cn(\n      \"flex flex-col space-y-1.5 text-center sm:text-left\",\n      className,\n    )}\n    {...props}\n  />\n);\nZoomDialogHeader.displayName = \"ZoomDialogHeader\";\n\nconst ZoomDialogFooter = ({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n  <div\n    className={cn(\n      \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n      className,\n    )}\n    {...props}\n  />\n);\nZoomDialogFooter.displayName = \"ZoomDialogFooter\";\n\nconst ZoomDialogTitle = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> & {\n  ref?: React.RefObject<React.ElementRef<typeof DialogPrimitive.Title> | null>;\n}) => (\n  <DialogPrimitive.Title\n    ref={ref}\n    className={cn(\n      \"text-lg font-semibold leading-none tracking-tight\",\n      className,\n    )}\n    {...props}\n  />\n);\nZoomDialogTitle.displayName = DialogPrimitive.Title.displayName;\n\nconst ZoomDialogDescription = ({\n  ref,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> & {\n  ref?: React.RefObject<React.ElementRef<\n    typeof DialogPrimitive.Description\n  > | null>;\n}) => (\n  <DialogPrimitive.Description\n    ref={ref}\n    className={cn(\"text-sm text-muted-foreground\", className)}\n    {...props}\n  />\n);\nZoomDialogDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n  ZoomDialog,\n  ZoomDialogClose,\n  ZoomDialogContent,\n  ZoomDialogDescription,\n  ZoomDialogFooter,\n  ZoomDialogHeader,\n  ZoomDialogOverlay,\n  ZoomDialogPortal,\n  ZoomDialogTitle,\n  ZoomDialogTrigger,\n};\n"
  },
  {
    "path": "packages/builder/src/constants/operator-help.ts",
    "content": "export interface OperatorHelp {\n  name: string;\n  description: string;\n  examples: Array<{\n    field: string;\n    operator: string;\n    value: string | number | boolean;\n    explanation: string;\n  }>;\n  tips?: string[];\n}\n\nexport const operatorHelp: Record<string, OperatorHelp> = {\n  // String Operators\n  equals: {\n    name: \"Equals\",\n    description:\n      \"Checks if the field value exactly matches the specified value. Case-sensitive.\",\n    examples: [\n      {\n        field: \"status\",\n        operator: \"equals\",\n        value: \"active\",\n        explanation: 'Matches when status is exactly \"active\"',\n      },\n      {\n        field: \"user.email\",\n        operator: \"equals\",\n        value: \"john@example.com\",\n        explanation: 'Matches when user email is exactly \"john@example.com\"',\n      },\n    ],\n    tips: [\n      'This is case-sensitive. \"Active\" will not match \"active\"',\n      'For case-insensitive matching, use \"equalsIgnoreCase\"',\n    ],\n  },\n\n  notEquals: {\n    name: \"Not Equals\",\n    description:\n      \"Checks if the field value does not match the specified value.\",\n    examples: [\n      {\n        field: \"status\",\n        operator: \"notEquals\",\n        value: \"inactive\",\n        explanation: 'Matches when status is anything except \"inactive\"',\n      },\n    ],\n    tips: [\n      \"Returns true for null or undefined values if they don't match the specified value\",\n    ],\n  },\n\n  contains: {\n    name: \"Contains\",\n    description:\n      \"Checks if the field value contains the specified substring. Case-sensitive.\",\n    examples: [\n      {\n        field: \"description\",\n        operator: \"contains\",\n        value: \"important\",\n        explanation: 'Matches when description contains \"important\" anywhere',\n      },\n      {\n        field: \"tags\",\n        operator: \"contains\",\n        value: \"beta\",\n        explanation: \"For arrays, checks if any element contains the substring\",\n      },\n    ],\n    tips: [\n      \"Works with both strings and arrays\",\n      \"For arrays, checks each element\",\n    ],\n  },\n\n  notContains: {\n    name: \"Not Contains\",\n    description:\n      \"Checks if the field value does not contain the specified substring.\",\n    examples: [\n      {\n        field: \"title\",\n        operator: \"notContains\",\n        value: \"draft\",\n        explanation: 'Matches when title doesn\\'t contain \"draft\"',\n      },\n    ],\n  },\n\n  startsWith: {\n    name: \"Starts With\",\n    description: \"Checks if the field value begins with the specified string.\",\n    examples: [\n      {\n        field: \"phone\",\n        operator: \"startsWith\",\n        value: \"+1\",\n        explanation: 'Matches phone numbers starting with \"+1\"',\n      },\n      {\n        field: \"sku\",\n        operator: \"startsWith\",\n        value: \"PROD-\",\n        explanation: 'Matches SKUs starting with \"PROD-\"',\n      },\n    ],\n  },\n\n  endsWith: {\n    name: \"Ends With\",\n    description: \"Checks if the field value ends with the specified string.\",\n    examples: [\n      {\n        field: \"email\",\n        operator: \"endsWith\",\n        value: \"@company.com\",\n        explanation: \"Matches company email addresses\",\n      },\n      {\n        field: \"filename\",\n        operator: \"endsWith\",\n        value: \".pdf\",\n        explanation: \"Matches PDF files\",\n      },\n    ],\n  },\n\n  matchesRegex: {\n    name: \"Matches Regex\",\n    description: \"Tests the field value against a regular expression pattern.\",\n    examples: [\n      {\n        field: \"email\",\n        operator: \"matchesRegex\",\n        value: \"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$\",\n        explanation: \"Validates email format\",\n      },\n      {\n        field: \"phone\",\n        operator: \"matchesRegex\",\n        value: \"^\\\\+?[1-9]\\\\d{1,14}$\",\n        explanation: \"Validates international phone number\",\n      },\n    ],\n    tips: [\n      \"Use JavaScript regex syntax\",\n      \"Escape special characters with backslash\",\n      \"Test your regex patterns before using\",\n    ],\n  },\n\n  // Number Operators\n  greaterThan: {\n    name: \"Greater Than\",\n    description:\n      \"Checks if the numeric field value is greater than the specified number.\",\n    examples: [\n      {\n        field: \"age\",\n        operator: \"greaterThan\",\n        value: 18,\n        explanation: \"Matches when age is 19 or higher\",\n      },\n      {\n        field: \"price\",\n        operator: \"greaterThan\",\n        value: 99.99,\n        explanation: \"Matches prices above $99.99\",\n      },\n    ],\n    tips: [\n      \"Works with integers and decimals\",\n      \"Returns false for non-numeric values\",\n    ],\n  },\n\n  greaterThanOrEquals: {\n    name: \"Greater Than or Equals\",\n    description:\n      \"Checks if the numeric field value is greater than or equal to the specified number.\",\n    examples: [\n      {\n        field: \"score\",\n        operator: \"greaterThanOrEquals\",\n        value: 80,\n        explanation: \"Matches scores of 80 or higher\",\n      },\n    ],\n  },\n\n  lessThan: {\n    name: \"Less Than\",\n    description:\n      \"Checks if the numeric field value is less than the specified number.\",\n    examples: [\n      {\n        field: \"inventory\",\n        operator: \"lessThan\",\n        value: 10,\n        explanation: \"Matches when inventory is below 10\",\n      },\n    ],\n  },\n\n  lessThanOrEquals: {\n    name: \"Less Than or Equals\",\n    description:\n      \"Checks if the numeric field value is less than or equal to the specified number.\",\n    examples: [\n      {\n        field: \"discount\",\n        operator: \"lessThanOrEquals\",\n        value: 50,\n        explanation: \"Matches discounts up to 50%\",\n      },\n    ],\n  },\n\n  between: {\n    name: \"Between\",\n    description:\n      \"Checks if the numeric field value falls within a range (inclusive).\",\n    examples: [\n      {\n        field: \"temperature\",\n        operator: \"between\",\n        value: \"20,30\",\n        explanation: \"Matches temperatures from 20 to 30 degrees\",\n      },\n    ],\n    tips: [\"Provide two comma-separated values\", \"Both bounds are inclusive\"],\n  },\n\n  // Boolean Operators\n  isTrue: {\n    name: \"Is True\",\n    description: \"Checks if the boolean field value is true.\",\n    examples: [\n      {\n        field: \"isActive\",\n        operator: \"isTrue\",\n        value: true,\n        explanation: \"Matches when isActive is true\",\n      },\n    ],\n    tips: [\n      \"No value input needed\",\n      \"Only matches boolean true, not truthy values\",\n    ],\n  },\n\n  isFalse: {\n    name: \"Is False\",\n    description: \"Checks if the boolean field value is false.\",\n    examples: [\n      {\n        field: \"isDeleted\",\n        operator: \"isFalse\",\n        value: false,\n        explanation: \"Matches when isDeleted is false\",\n      },\n    ],\n  },\n\n  // Date Operators\n  before: {\n    name: \"Before\",\n    description: \"Checks if the date field value is before the specified date.\",\n    examples: [\n      {\n        field: \"createdAt\",\n        operator: \"before\",\n        value: \"2025-01-01\",\n        explanation: \"Matches records created before January 1, 2025\",\n      },\n    ],\n    tips: [\n      \"Accepts various date formats\",\n      \"Time component is considered if provided\",\n    ],\n  },\n\n  after: {\n    name: \"After\",\n    description: \"Checks if the date field value is after the specified date.\",\n    examples: [\n      {\n        field: \"expiryDate\",\n        operator: \"after\",\n        value: \"2025-12-31\",\n        explanation: \"Matches items expiring after December 31, 2025\",\n      },\n    ],\n  },\n\n  dateEquals: {\n    name: \"Date Equals\",\n    description: \"Checks if the date field value matches the specified date.\",\n    examples: [\n      {\n        field: \"birthday\",\n        operator: \"dateEquals\",\n        value: \"1990-05-15\",\n        explanation: \"Matches birthdays on May 15, 1990\",\n      },\n    ],\n    tips: [\n      \"Compares date portion only by default\",\n      \"Include time for precise matching\",\n    ],\n  },\n\n  dateBetween: {\n    name: \"Date Between\",\n    description: \"Checks if the date falls within a date range.\",\n    examples: [\n      {\n        field: \"orderDate\",\n        operator: \"dateBetween\",\n        value: \"2025-01-01,2025-12-31\",\n        explanation: \"Matches orders placed in 2025\",\n      },\n    ],\n    tips: [\"Provide two comma-separated dates\", \"Both bounds are inclusive\"],\n  },\n\n  // Array Operators\n  in: {\n    name: \"In\",\n    description: \"Checks if the field value is included in a list of values.\",\n    examples: [\n      {\n        field: \"status\",\n        operator: \"in\",\n        value: \"pending,processing,shipped\",\n        explanation: \"Matches any of these three statuses\",\n      },\n      {\n        field: \"role\",\n        operator: \"in\",\n        value: \"admin,moderator\",\n        explanation: \"Matches admin or moderator roles\",\n      },\n    ],\n    tips: [\n      \"Provide comma-separated values\",\n      \"Useful for multiple allowed values\",\n    ],\n  },\n\n  notIn: {\n    name: \"Not In\",\n    description:\n      \"Checks if the field value is not included in a list of values.\",\n    examples: [\n      {\n        field: \"status\",\n        operator: \"notIn\",\n        value: \"deleted,archived\",\n        explanation: \"Matches any status except deleted or archived\",\n      },\n    ],\n  },\n\n  arrayContains: {\n    name: \"Array Contains\",\n    description: \"Checks if an array field contains a specific value.\",\n    examples: [\n      {\n        field: \"tags\",\n        operator: \"arrayContains\",\n        value: \"featured\",\n        explanation: 'Matches when tags array includes \"featured\"',\n      },\n    ],\n    tips: [\"Field must be an array\", \"Checks for exact value match in array\"],\n  },\n\n  arrayContainsAny: {\n    name: \"Array Contains Any\",\n    description:\n      \"Checks if an array field contains any of the specified values.\",\n    examples: [\n      {\n        field: \"permissions\",\n        operator: \"arrayContainsAny\",\n        value: \"read,write,delete\",\n        explanation: \"Matches if user has any of these permissions\",\n      },\n    ],\n  },\n\n  arrayContainsAll: {\n    name: \"Array Contains All\",\n    description:\n      \"Checks if an array field contains all of the specified values.\",\n    examples: [\n      {\n        field: \"requiredSkills\",\n        operator: \"arrayContainsAll\",\n        value: \"javascript,react,typescript\",\n        explanation: \"Matches only if all three skills are present\",\n      },\n    ],\n  },\n\n  // Null/Existence Operators\n  isNull: {\n    name: \"Is Null\",\n    description: \"Checks if the field value is null.\",\n    examples: [\n      {\n        field: \"deletedAt\",\n        operator: \"isNull\",\n        value: \"\",\n        explanation: \"Matches records that haven't been deleted\",\n      },\n    ],\n    tips: [\n      \"No value input needed\",\n      \"Only matches null, not undefined or empty string\",\n    ],\n  },\n\n  isNotNull: {\n    name: \"Is Not Null\",\n    description: \"Checks if the field value is not null.\",\n    examples: [\n      {\n        field: \"email\",\n        operator: \"isNotNull\",\n        value: \"\",\n        explanation: \"Matches records with an email value\",\n      },\n    ],\n  },\n\n  isEmpty: {\n    name: \"Is Empty\",\n    description:\n      \"Checks if the field value is empty (null, undefined, empty string, or empty array).\",\n    examples: [\n      {\n        field: \"description\",\n        operator: \"isEmpty\",\n        value: \"\",\n        explanation: \"Matches when description is empty or not set\",\n      },\n    ],\n    tips: [\n      \"Works with strings, arrays, and objects\",\n      'Considers \"\", [], {}, null, and undefined as empty',\n    ],\n  },\n\n  isNotEmpty: {\n    name: \"Is Not Empty\",\n    description: \"Checks if the field value is not empty.\",\n    examples: [\n      {\n        field: \"tags\",\n        operator: \"isNotEmpty\",\n        value: \"\",\n        explanation: \"Matches when tags array has at least one item\",\n      },\n    ],\n  },\n};\n"
  },
  {
    "path": "packages/builder/src/data/sample-data.ts",
    "content": "// Comprehensive sample data for showcasing the rule builder\nimport type { FieldConfig } from \"../types\";\n\nexport const sampleEcommerceData = {\n  user: {\n    id: \"usr_123456\",\n    name: \"John Doe\",\n    email: \"john.doe@example.com\",\n    age: 32,\n    status: \"active\",\n    role: \"premium\",\n    createdAt: \"2023-01-15T10:30:00Z\",\n    lastLoginAt: \"2025-01-20T14:22:00Z\",\n    profile: {\n      avatar: \"https://example.com/avatar/john.jpg\",\n      bio: \"Software developer and tech enthusiast\",\n      preferences: {\n        newsletter: true,\n        notifications: {\n          email: true,\n          push: false,\n          sms: true,\n        },\n        theme: \"dark\",\n        language: \"en\",\n        timezone: \"America/New_York\",\n      },\n      social: {\n        twitter: \"@johndoe\",\n        linkedin: \"john-doe-123\",\n        github: \"johndoe\",\n      },\n    },\n    address: {\n      billing: {\n        street: \"123 Main St\",\n        city: \"New York\",\n        state: \"NY\",\n        zip: \"10001\",\n        country: \"USA\",\n        isDefault: true,\n      },\n      shipping: [\n        {\n          id: \"addr_1\",\n          label: \"Home\",\n          street: \"123 Main St\",\n          city: \"New York\",\n          state: \"NY\",\n          zip: \"10001\",\n          country: \"USA\",\n          isDefault: true,\n        },\n        {\n          id: \"addr_2\",\n          label: \"Office\",\n          street: \"456 Business Ave\",\n          city: \"New York\",\n          state: \"NY\",\n          zip: \"10002\",\n          country: \"USA\",\n          isDefault: false,\n        },\n      ],\n    },\n    membership: {\n      tier: \"gold\",\n      points: 15420,\n      expiresAt: \"2025-12-31T23:59:59Z\",\n      benefits: [\"free_shipping\", \"priority_support\", \"exclusive_deals\"],\n      history: [\n        { tier: \"bronze\", startDate: \"2023-01-15\", endDate: \"2023-06-30\" },\n        { tier: \"silver\", startDate: \"2023-07-01\", endDate: \"2023-12-31\" },\n        { tier: \"gold\", startDate: \"2025-01-01\", endDate: null },\n      ],\n    },\n  },\n  cart: {\n    id: \"cart_789012\",\n    items: [\n      {\n        id: \"item_1\",\n        productId: \"prod_001\",\n        name: \"Wireless Headphones\",\n        category: \"electronics\",\n        price: 149.99,\n        quantity: 1,\n        discount: 0.1,\n        attributes: {\n          color: \"black\",\n          warranty: \"2 years\",\n          brand: \"TechSound\",\n        },\n      },\n      {\n        id: \"item_2\",\n        productId: \"prod_002\",\n        name: \"Smart Watch\",\n        category: \"electronics\",\n        price: 299.99,\n        quantity: 2,\n        discount: 0.15,\n        attributes: {\n          color: \"silver\",\n          size: \"42mm\",\n          brand: \"TimeTech\",\n        },\n      },\n      {\n        id: \"item_3\",\n        productId: \"prod_003\",\n        name: \"Running Shoes\",\n        category: \"sports\",\n        price: 89.99,\n        quantity: 1,\n        discount: 0,\n        attributes: {\n          color: \"blue\",\n          size: \"10\",\n          brand: \"RunFast\",\n        },\n      },\n    ],\n    subtotal: 839.96,\n    tax: 67.2,\n    shipping: 9.99,\n    discount: 134.99,\n    total: 782.16,\n    couponCode: \"SAVE15\",\n    isGift: false,\n  },\n  order: {\n    recent: [\n      {\n        id: \"ord_456789\",\n        date: \"2025-01-10T16:45:00Z\",\n        status: \"delivered\",\n        total: 567.89,\n        items: 3,\n        trackingNumber: \"1Z999AA1234567890\",\n      },\n      {\n        id: \"ord_456790\",\n        date: \"2023-12-25T09:30:00Z\",\n        status: \"delivered\",\n        total: 234.56,\n        items: 2,\n        trackingNumber: \"1Z999AA0987654321\",\n      },\n    ],\n    statistics: {\n      totalOrders: 45,\n      totalSpent: 12456.78,\n      averageOrderValue: 276.82,\n      lastOrderDaysAgo: 10,\n    },\n  },\n  payment: {\n    methods: [\n      {\n        id: \"pay_001\",\n        type: \"credit_card\",\n        brand: \"visa\",\n        last4: \"4242\",\n        expiryMonth: 12,\n        expiryYear: 2025,\n        isDefault: true,\n        billingAddress: \"addr_1\",\n      },\n      {\n        id: \"pay_002\",\n        type: \"paypal\",\n        email: \"john.doe@example.com\",\n        isDefault: false,\n      },\n    ],\n    wallet: {\n      balance: 125.5,\n      currency: \"USD\",\n      transactions: [\n        {\n          id: \"txn_001\",\n          type: \"credit\",\n          amount: 50.0,\n          date: \"2025-01-15T10:00:00Z\",\n          description: \"Refund for order #456788\",\n        },\n        {\n          id: \"txn_002\",\n          type: \"debit\",\n          amount: 25.0,\n          date: \"2025-01-18T14:30:00Z\",\n          description: \"Applied to order #456791\",\n        },\n      ],\n    },\n  },\n  recommendations: {\n    products: [\n      {\n        id: \"prod_rec_001\",\n        name: \"Laptop Stand\",\n        category: \"accessories\",\n        price: 49.99,\n        score: 0.95,\n        reason: \"frequently_bought_together\",\n      },\n      {\n        id: \"prod_rec_002\",\n        name: \"USB-C Hub\",\n        category: \"accessories\",\n        price: 39.99,\n        score: 0.89,\n        reason: \"similar_interests\",\n      },\n    ],\n    categories: [\"electronics\", \"accessories\", \"sports\"],\n    basedOn: [\"purchase_history\", \"browsing_behavior\", \"similar_users\"],\n  },\n  session: {\n    id: \"sess_abc123\",\n    startTime: \"2025-01-20T14:00:00Z\",\n    lastActivity: \"2025-01-20T14:35:00Z\",\n    pageViews: 12,\n    device: {\n      type: \"desktop\",\n      browser: \"chrome\",\n      os: \"macOS\",\n      screenResolution: \"2560x1440\",\n    },\n    location: {\n      country: \"USA\",\n      region: \"NY\",\n      city: \"New York\",\n      ip: \"192.168.1.1\",\n    },\n    referrer: \"google.com\",\n    utmSource: \"email\",\n    utmCampaign: \"winter_sale_2025\",\n  },\n};\n\n// Field configurations for the rule builder\nexport const ecommerceFields: FieldConfig[] = [\n  // User fields\n  {\n    name: \"user.age\",\n    label: \"User Age\",\n    type: \"number\",\n    description: \"Age of the user in years\",\n  },\n  {\n    name: \"user.status\",\n    label: \"User Status\",\n    type: \"string\",\n    values: [\n      { value: \"active\", label: \"Active\" },\n      { value: \"inactive\", label: \"Inactive\" },\n      { value: \"suspended\", label: \"Suspended\" },\n    ],\n    description: \"Current account status\",\n  },\n  {\n    name: \"user.role\",\n    label: \"User Role\",\n    type: \"string\",\n    values: [\n      { value: \"basic\", label: \"Basic\" },\n      { value: \"premium\", label: \"Premium\" },\n      { value: \"vip\", label: \"VIP\" },\n    ],\n    description: \"User subscription tier\",\n  },\n  {\n    name: \"user.membership.tier\",\n    label: \"Membership Tier\",\n    type: \"string\",\n    values: [\n      { value: \"bronze\", label: \"Bronze\" },\n      { value: \"silver\", label: \"Silver\" },\n      { value: \"gold\", label: \"Gold\" },\n      { value: \"platinum\", label: \"Platinum\" },\n    ],\n    description: \"Current membership level\",\n  },\n  {\n    name: \"user.membership.points\",\n    label: \"Loyalty Points\",\n    type: \"number\",\n    description: \"Total accumulated loyalty points\",\n  },\n  // Cart fields\n  {\n    name: \"cart.total\",\n    label: \"Cart Total\",\n    type: \"number\",\n    description: \"Total cart value including tax and shipping\",\n  },\n  {\n    name: \"cart.items.length\",\n    label: \"Items in Cart\",\n    type: \"number\",\n    description: \"Number of items in the shopping cart\",\n  },\n  // Order fields\n  {\n    name: \"order.statistics.totalOrders\",\n    label: \"Total Orders\",\n    type: \"number\",\n    description: \"Lifetime number of orders placed\",\n  },\n  {\n    name: \"order.statistics.totalSpent\",\n    label: \"Total Spent\",\n    type: \"number\",\n    description: \"Lifetime amount spent\",\n  },\n  {\n    name: \"order.statistics.averageOrderValue\",\n    label: \"Average Order Value\",\n    type: \"number\",\n    description: \"Average value per order\",\n  },\n  // Session fields\n  {\n    name: \"session.device.type\",\n    label: \"Device Type\",\n    type: \"string\",\n    values: [\n      { value: \"desktop\", label: \"Desktop\" },\n      { value: \"mobile\", label: \"Mobile\" },\n      { value: \"tablet\", label: \"Tablet\" },\n    ],\n    description: \"Type of device being used\",\n  },\n  {\n    name: \"session.location.country\",\n    label: \"Country\",\n    type: \"string\",\n    description: \"User's country based on IP\",\n  },\n];\n"
  },
  {
    "path": "packages/builder/src/debug-test.tsx",
    "content": "import React from \"react\";\nimport { useRuleBuilder } from \"./stores/unified-rule-store\";\nimport { ConditionTypes } from \"@usex/rule-engine\";\nimport { Button } from \"./components/ui/button\";\nimport {\n  CardTitle,\n  CardHeader,\n  CardDescription,\n  CardContent,\n  Card,\n} from \"./components/ui/card\";\nimport { Badge } from \"./components/ui/badge\";\nimport { JsonViewer } from \"./components/JsonVisualizer\";\nimport {\n  Zap,\n  Trash2,\n  Settings,\n  RefreshCw,\n  Plus,\n  Play,\n  GitBranch,\n  Code2,\n  CheckCircle2,\n} from \"lucide-react\";\n\nfunction TestComponent() {\n  const { state, addCondition, addConstraint, resetRule } = useRuleBuilder();\n\n  const [testStatus, setTestStatus] = React.useState<{\n    running: boolean;\n    currentStep: string;\n    success: boolean;\n  }>({ running: false, currentStep: \"\", success: false });\n\n  const executeWithStatus = async (\n    steps: Array<{ action: () => void; description: string }>,\n  ) => {\n    setTestStatus({ running: true, currentStep: \"\", success: false });\n\n    for (let i = 0; i < steps.length; i++) {\n      const step = steps[i];\n      setTestStatus((prev) => ({ ...prev, currentStep: step.description }));\n      console.log(`Step ${i + 1}: ${step.description}`);\n      step.action();\n      await new Promise((resolve) => setTimeout(resolve, 800));\n    }\n\n    setTestStatus({ running: false, currentStep: \"Complete!\", success: true });\n    setTimeout(() => {\n      setTestStatus({ running: false, currentStep: \"\", success: false });\n    }, 3000);\n  };\n\n  const handleAddRootCondition = () => {\n    console.log(\"Adding root condition\");\n    addCondition(\"\", ConditionTypes.AND);\n  };\n\n  const handleAddNestedCondition = () => {\n    console.log(\"Adding nested condition\");\n    addCondition(\"and\", ConditionTypes.OR);\n  };\n\n  const handleAddConstraint = () => {\n    console.log(\"Adding constraint to root\");\n    addConstraint(\"and\", {\n      field: \"user.age\",\n      operator: \"equals\" as any,\n      value: 25,\n    });\n  };\n\n  const handleReset = () => {\n    console.log(\"Resetting rule\");\n    resetRule();\n    setTestStatus({ running: false, currentStep: \"\", success: false });\n  };\n\n  const handleTestComplexStructure = async () => {\n    await executeWithStatus([\n      { action: () => resetRule(), description: \"Resetting to clean state\" },\n      {\n        action: () => addCondition(\"\", ConditionTypes.AND),\n        description: \"Creating root AND condition\",\n      },\n      {\n        action: () =>\n          addConstraint(\"and\", {\n            field: \"user.age\",\n            operator: \"greater_than\" as any,\n            value: 18,\n          }),\n        description: \"Adding age constraint\",\n      },\n      {\n        action: () => addCondition(\"and\", ConditionTypes.OR),\n        description: \"Adding nested OR condition\",\n      },\n      {\n        action: () =>\n          addConstraint(\"and.0.or\", {\n            field: \"user.name\",\n            operator: \"equals\" as any,\n            value: \"Alice\",\n          }),\n        description: \"Adding Alice constraint\",\n      },\n      {\n        action: () =>\n          addConstraint(\"and.0.or\", {\n            field: \"user.name\",\n            operator: \"equals\" as any,\n            value: \"Bob\",\n          }),\n        description: \"Adding Bob constraint\",\n      },\n    ]);\n  };\n\n  const handleTestComprehensive = async () => {\n    await executeWithStatus([\n      { action: () => resetRule(), description: \"Resetting to clean state\" },\n      {\n        action: () => addCondition(\"\", ConditionTypes.AND),\n        description: \"Creating root AND condition\",\n      },\n      {\n        action: () =>\n          addConstraint(\"and\", {\n            field: \"user.age\",\n            operator: \"greater_than\" as any,\n            value: 18,\n          }),\n        description: \"Adding age > 18 constraint\",\n      },\n      {\n        action: () =>\n          addConstraint(\"and\", {\n            field: \"user.role\",\n            operator: \"equals\" as any,\n            value: \"admin\",\n          }),\n        description: \"Adding admin role constraint\",\n      },\n      {\n        action: () => addCondition(\"and\", ConditionTypes.OR),\n        description: \"Adding nested OR condition\",\n      },\n      {\n        action: () =>\n          addConstraint(\"and.1.or\", {\n            field: \"user.department\",\n            operator: \"equals\" as any,\n            value: \"IT\",\n          }),\n        description: \"Adding IT department constraint\",\n      },\n      {\n        action: () =>\n          addConstraint(\"and.1.or\", {\n            field: \"user.department\",\n            operator: \"equals\" as any,\n            value: \"Security\",\n          }),\n        description: \"Adding Security department constraint\",\n      },\n    ]);\n  };\n\n  const hasConditions = React.useMemo(() => {\n    if (!state.rule.conditions) return false;\n    const condition = state.rule.conditions as any;\n\n    // Check if the conditions object is empty (no keys)\n    if (Object.keys(condition).length === 0) return false;\n\n    return (\n      (condition.and && condition.and.length > 0) ||\n      (condition.or && condition.or.length > 0) ||\n      (condition.none && condition.none.length > 0)\n    );\n  }, [state.rule.conditions]);\n\n  const getConditionCount = () => {\n    if (!hasConditions) return 0;\n    const condition = state.rule.conditions as any;\n    const andCount = condition.and?.length || 0;\n    const orCount = condition.or?.length || 0;\n    const noneCount = condition.none?.length || 0;\n    return andCount + orCount + noneCount;\n  };\n\n  return (\n    <div className=\"max-w-6xl mx-auto p-6 space-y-6\">\n      {/* Header */}\n      <div className=\"flex items-center justify-between\">\n        <div>\n          <h1 className=\"text-3xl font-bold text-gray-900 dark:text-white flex items-center gap-3\">\n            <Code2 className=\"h-8 w-8 text-blue-600 dark:text-blue-400\" />\n            Debug Testing Suite\n          </h1>\n          <p className=\"text-gray-600 dark:text-gray-400 mt-2\">\n            Interactive testing environment for rule engine operations\n          </p>\n        </div>\n        <div className=\"flex items-center gap-2\">\n          <Badge variant={hasConditions ? \"default\" : \"secondary\"}>\n            {getConditionCount()} Items\n          </Badge>\n          <Badge variant={state.isDirty ? \"destructive\" : \"outline\"}>\n            {state.isDirty ? \"Modified\" : \"Clean\"}\n          </Badge>\n        </div>\n      </div>\n\n      {/* Test Status */}\n      {testStatus.running && (\n        <Card className=\"border-blue-200 dark:border-blue-800 bg-blue-50 dark:bg-blue-950/50\">\n          <CardContent className=\"p-4\">\n            <div className=\"flex items-center gap-3\">\n              <div className=\"animate-spin\">\n                <RefreshCw className=\"h-4 w-4 text-blue-600\" />\n              </div>\n              <span className=\"text-sm font-medium text-blue-900 dark:text-blue-100\">\n                {testStatus.currentStep}\n              </span>\n            </div>\n          </CardContent>\n        </Card>\n      )}\n\n      {testStatus.success && (\n        <Card className=\"border-green-200 dark:border-green-800 bg-green-50 dark:bg-green-950/50\">\n          <CardContent className=\"p-4\">\n            <div className=\"flex items-center gap-3\">\n              <CheckCircle2 className=\"h-4 w-4 text-green-600\" />\n              <span className=\"text-sm font-medium text-green-900 dark:text-green-100\">\n                Test sequence completed successfully!\n              </span>\n            </div>\n          </CardContent>\n        </Card>\n      )}\n\n      <div className=\"grid lg:grid-cols-2 gap-6\">\n        {/* Basic Operations */}\n        <Card>\n          <CardHeader>\n            <CardTitle className=\"flex items-center gap-2 text-gray-900 dark:text-white\">\n              <Settings className=\"h-5 w-5 text-gray-600 dark:text-gray-400\" />\n              Basic Operations\n            </CardTitle>\n            <CardDescription>\n              Test individual rule engine operations\n            </CardDescription>\n          </CardHeader>\n          <CardContent className=\"space-y-3\">\n            <div className=\"grid grid-cols-2 gap-2\">\n              <Button\n                onClick={handleAddRootCondition}\n                variant=\"outline\"\n                className=\"flex items-center gap-2\"\n              >\n                <Plus className=\"h-4 w-4\" />\n                Root Condition\n              </Button>\n              <Button\n                onClick={handleAddNestedCondition}\n                variant=\"outline\"\n                className=\"flex items-center gap-2\"\n                disabled={!hasConditions}\n              >\n                <GitBranch className=\"h-4 w-4\" />\n                Nested Condition\n              </Button>\n              <Button\n                onClick={handleAddConstraint}\n                variant=\"outline\"\n                className=\"flex items-center gap-2\"\n                disabled={!hasConditions}\n              >\n                <Plus className=\"h-4 w-4\" />\n                Add Constraint\n              </Button>\n              <Button\n                onClick={handleReset}\n                variant=\"destructive\"\n                className=\"flex items-center gap-2\"\n              >\n                <Trash2 className=\"h-4 w-4\" />\n                Reset All\n              </Button>\n            </div>\n          </CardContent>\n        </Card>\n\n        {/* Advanced Tests */}\n        <Card>\n          <CardHeader>\n            <CardTitle className=\"flex items-center gap-2 text-gray-900 dark:text-white\">\n              <Zap className=\"h-5 w-5 text-yellow-600 dark:text-yellow-400\" />\n              Advanced Tests\n            </CardTitle>\n            <CardDescription>\n              Automated test sequences for complex structures\n            </CardDescription>\n          </CardHeader>\n          <CardContent className=\"space-y-3\">\n            <Button\n              onClick={handleTestComplexStructure}\n              className=\"w-full flex items-center gap-2\"\n              disabled={testStatus.running}\n            >\n              <Play className=\"h-4 w-4\" />\n              Complex Structure Test\n            </Button>\n            <Button\n              onClick={handleTestComprehensive}\n              variant=\"secondary\"\n              className=\"w-full flex items-center gap-2\"\n              disabled={testStatus.running}\n            >\n              <Play className=\"h-4 w-4\" />\n              Comprehensive Test Suite\n            </Button>\n          </CardContent>\n        </Card>\n      </div>\n\n      {/* Rule Output */}\n      <Card>\n        <CardHeader>\n          <CardTitle className=\"flex items-center gap-2 text-gray-900 dark:text-white\">\n            <Code2 className=\"h-5 w-5 text-purple-600 dark:text-purple-400\" />\n            Current Rule State\n          </CardTitle>\n          <CardDescription>\n            JSON representation of the current rule structure\n          </CardDescription>\n        </CardHeader>\n        <CardContent>\n          <div className=\"bg-gray-50 dark:bg-background p-4 rounded-lg border border-gray-200 dark:border-gray-700\">\n            <JsonViewer\n              data={state.rule}\n              rootName=\"rule\"\n              defaultExpanded={true}\n              highlightLogicalOperators={true}\n              className=\"text-gray-900 dark:text-gray-100\"\n            />\n          </div>\n        </CardContent>\n      </Card>\n    </div>\n  );\n}\n\nexport function DebugTest() {\n  return <TestComponent />;\n}\n\nexport default DebugTest;\n"
  },
  {
    "path": "packages/builder/src/demo.tsx",
    "content": "import { useState, useEffect, StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { RuleBuilder } from \"./components/rule-builder\";\nimport { DebugTest } from \"./debug-test\";\nimport { Analytics } from \"@vercel/analytics/react\";\nimport { SpeedInsights } from \"@vercel/speed-insights/react\";\nimport { StoreDebugTest } from \"./test-store-debug\";\nimport {\n  Zap,\n  Star,\n  Sparkles,\n  Smartphone,\n  Shield,\n  Moon,\n  Layers,\n  Github,\n  GitFork,\n  ExternalLink,\n  Code2,\n  ChevronRight,\n  ArrowRight,\n} from \"lucide-react\";\nimport { ecommerceFields } from \"./data/sample-data\";\nimport { operatorConfigs } from \"./utils/operators\";\nimport \"./styles/globals.css\";\nimport \"./styles/animations.css\";\n\n// Initialize theme\nif (typeof window !== \"undefined\") {\n  const root = document.documentElement;\n  const theme = localStorage.getItem(\"rule-builder-theme\") || \"system\";\n\n  if (theme === \"system\") {\n    const systemTheme = window.matchMedia(\"(prefers-color-scheme: dark)\")\n      .matches\n      ? \"dark\"\n      : \"light\";\n    root.classList.add(systemTheme);\n  } else {\n    root.classList.add(theme);\n  }\n}\n\ninterface StatsData {\n  downloads: string;\n  contributors: string;\n  stars: string;\n  loading: boolean;\n}\n\nfunction DemoApp() {\n  const [mode, setMode] = useState<\"builder\" | \"debug\" | \"store-debug\">(\n    \"builder\",\n  );\n  const [scrolled, setScrolled] = useState(false);\n  const [stats, setStats] = useState<StatsData>({\n    downloads: \"50k+\",\n    contributors: \"100+\",\n    stars: \"4.9★\",\n    loading: true,\n  });\n\n  useEffect(() => {\n    const handleScroll = () => {\n      setScrolled(window.scrollY > 20);\n    };\n    window.addEventListener(\"scroll\", handleScroll);\n    return () => window.removeEventListener(\"scroll\", handleScroll);\n  }, []);\n\n  useEffect(() => {\n    const fetchStats = async () => {\n      try {\n        // Fetch npm downloads - try both package names\n        const npmResponse = await fetch(\n          \"https://api.npmjs.org/downloads/range/last-year/@usex/rule-engine-builder\",\n        ).catch(() =>\n          fetch(\n            \"https://api.npmjs.org/downloads/range/last-year/@usex/rule-engine\",\n          ),\n        );\n\n        // Fetch GitHub data\n        const githubResponse = await fetch(\n          \"https://api.github.com/repos/ali-master/rule-engine\",\n        );\n\n        // Fetch contributors\n        const contributorsResponse = await fetch(\n          \"https://api.github.com/repos/ali-master/rule-engine/contributors\",\n        );\n\n        if (npmResponse.ok && githubResponse.ok && contributorsResponse.ok) {\n          const npmData = await npmResponse.json();\n          const githubData = await githubResponse.json();\n          const contributorsData = await contributorsResponse.json();\n\n          // Calculate total downloads\n          const totalDownloads =\n            npmData.downloads?.reduce(\n              (total: number, day: { downloads: number }) =>\n                total + day.downloads,\n              0,\n            ) || 0;\n\n          // Format numbers\n          const formatNumber = (num: number) => {\n            if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`;\n            if (num >= 1000) return `${(num / 1000).toFixed(0)}k`;\n            return num.toString();\n          };\n\n          const formatStars = (stars: number) => {\n            // Use actual star count, format it nicely\n            if (stars >= 1000) {\n              return `${(stars / 1000).toFixed(1)}k★`;\n            }\n            return `${stars}★`;\n          };\n\n          setStats({\n            downloads: `${formatNumber(totalDownloads)}+`,\n            contributors: `${contributorsData.length}+`,\n            stars: formatStars(githubData.stargazers_count),\n            loading: false,\n          });\n        }\n      } catch (error) {\n        console.warn(\"Failed to fetch stats:\", error);\n        // Keep default values if API fails\n        setStats((prev) => ({ ...prev, loading: false }));\n      }\n    };\n\n    void fetchStats();\n  }, []);\n\n  return (\n    <div className=\"min-h-screen w-full relative bg-black overflow-x-hidden\">\n      {/* Animated Background with Multiple Layers */}\n      <div className=\"fixed inset-0 z-0\">\n        {/* Primary gradient */}\n        <div\n          className=\"absolute inset-0\"\n          style={{\n            background:\n              \"radial-gradient(ellipse 80% 80% at 50% -20%, rgba(6, 182, 212, 0.25), transparent 70%), #000000\",\n          }}\n        />\n\n        {/* Animated gradient orbs */}\n        <div className=\"absolute inset-0 overflow-hidden\">\n          <div className=\"absolute -top-40 -left-40 w-96 h-96 bg-cyan-500/20 rounded-full blur-3xl animate-pulse\" />\n          <div className=\"absolute top-1/2 -right-40 w-96 h-96 bg-purple-500/20 rounded-full blur-3xl animate-pulse animation-delay-2000\" />\n          <div className=\"absolute -bottom-40 left-1/2 w-96 h-96 bg-blue-500/20 rounded-full blur-3xl animate-pulse animation-delay-4000\" />\n        </div>\n\n        {/* Grid pattern overlay */}\n        <div\n          className=\"absolute inset-0 opacity-[0.02]\"\n          style={{\n            backgroundImage: `url(\"data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='1'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E\")`,\n          }}\n        />\n      </div>\n      {/* Enhanced Modern Header */}\n      <header\n        className={`fixed w-full top-0 z-50 transition-all duration-300 ${\n          scrolled\n            ? \"bg-black/90 backdrop-blur-xl border-b border-white/10\"\n            : \"bg-transparent\"\n        }`}\n      >\n        <div className=\"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8\">\n          <div className=\"flex items-center justify-between h-16 sm:h-20\">\n            {/* Logo and Brand */}\n            <div className=\"flex items-center gap-3 sm:gap-4\">\n              <div className=\"relative group\">\n                <div className=\"absolute inset-0 bg-gradient-to-r from-cyan-500 to-blue-500 rounded-xl blur-lg group-hover:blur-xl transition-all duration-300 opacity-75\" />\n                <div className=\"relative bg-gradient-to-r from-cyan-500 to-blue-500 p-2.5 rounded-xl\">\n                  <Layers className=\"w-6 h-6 sm:w-7 sm:h-7 text-white\" />\n                </div>\n              </div>\n              <div>\n                <h1 className=\"text-xl sm:text-2xl font-bold text-white tracking-tight\">\n                  Rule Engine\n                </h1>\n                <p className=\"text-xs sm:text-sm text-gray-400 hidden sm:block\">\n                  Visual Logic Designer\n                </p>\n              </div>\n            </div>\n\n            {/* Navigation and Actions */}\n            <nav className=\"flex items-center gap-6\">\n              {/* Desktop Navigation */}\n              <div className=\"hidden lg:flex items-center gap-6\">\n                <a\n                  href=\"#features\"\n                  className=\"text-gray-300 hover:text-white transition-colors text-sm font-medium\"\n                >\n                  Features\n                </a>\n                <a\n                  href=\"#demo\"\n                  className=\"text-gray-300 hover:text-white transition-colors text-sm font-medium\"\n                >\n                  Demo\n                </a>\n                <a\n                  href=\"https://github.com/ali-master/rule-engine\"\n                  className=\"text-gray-300 hover:text-white transition-colors text-sm font-medium\"\n                >\n                  Documentation\n                </a>\n              </div>\n\n              {/* Action Buttons */}\n              <div className=\"flex items-center gap-3\">\n                <a\n                  href=\"https://github.com/ali-master/rule-engine\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                  className=\"hidden sm:flex items-center gap-2 px-4 py-2 text-sm font-medium text-gray-300 hover:text-white transition-all duration-200 hover:bg-white/5 rounded-lg\"\n                >\n                  <Github className=\"w-4 h-4\" />\n                  <span>GitHub</span>\n                </a>\n\n                <a\n                  href=\"https://github.com/ali-master/rule-engine\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                  className=\"relative group\"\n                >\n                  <div className=\"absolute inset-0 bg-gradient-to-r from-cyan-500 to-blue-500 rounded-lg blur group-hover:blur-md transition-all duration-300\" />\n                  <div className=\"relative flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-cyan-500 to-blue-500 text-white rounded-lg font-medium text-sm hover:shadow-lg transition-all duration-200\">\n                    <Star className=\"w-4 h-4\" />\n                    <span>Star</span>\n                  </div>\n                </a>\n              </div>\n            </nav>\n          </div>\n        </div>\n      </header>\n\n      {/* Main Content */}\n      <main className=\"relative z-10\">\n        {/* Hero Section - Enhanced */}\n        <section className=\"relative min-h-screen flex items-center justify-center px-4 sm:px-6 lg:px-8 pt-20\">\n          <div className=\"max-w-7xl mx-auto text-center\">\n            {/* Floating elements */}\n            <div className=\"absolute inset-0 overflow-hidden pointer-events-none\">\n              <div className=\"absolute top-1/4 left-10 w-72 h-72 bg-gradient-to-br from-cyan-500/10 to-blue-500/10 rounded-full blur-3xl animate-float\" />\n              <div className=\"absolute bottom-1/4 right-10 w-96 h-96 bg-gradient-to-br from-purple-500/10 to-pink-500/10 rounded-full blur-3xl animate-float animation-delay-2000\" />\n            </div>\n\n            {/* Hero Content */}\n            <div className=\"relative space-y-8\">\n              {/* Badge */}\n              <div className=\"inline-flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-cyan-500/10 to-blue-500/10 border border-cyan-500/20 rounded-full\">\n                <Sparkles className=\"w-4 h-4 text-cyan-400\" />\n                <span className=\"text-sm font-medium text-cyan-300\">\n                  Visual Business Logic Designer\n                </span>\n              </div>\n\n              {/* Main Title */}\n              <div className=\"space-y-4\">\n                <h1 className=\"text-5xl sm:text-6xl lg:text-7xl font-bold tracking-tight\">\n                  <span className=\"text-white\">Build Complex</span>\n                  <br />\n                  <span className=\"bg-gradient-to-r from-cyan-400 via-blue-400 to-purple-400 bg-clip-text text-transparent\">\n                    Business Rules\n                  </span>\n                  <br />\n                  <span className=\"text-white\">Visually</span>\n                </h1>\n\n                <p className=\"text-lg sm:text-xl text-gray-400 max-w-3xl mx-auto leading-relaxed\">\n                  Transform your IF-THEN logic into powerful, maintainable rule\n                  configurations. Design, test, and deploy business rules with\n                  our intuitive visual interface.\n                </p>\n              </div>\n\n              {/* CTA Buttons */}\n              <div className=\"flex flex-col sm:flex-row items-center justify-center gap-4 pt-4\">\n                <a\n                  href=\"#demo\"\n                  className=\"group relative inline-flex items-center gap-2 px-8 py-4 overflow-hidden rounded-xl font-semibold transition-all duration-300\"\n                >\n                  <div className=\"absolute inset-0 bg-gradient-to-r from-cyan-500 to-blue-500 transition-all duration-300 group-hover:scale-105\" />\n                  <span className=\"relative flex items-center gap-2 text-white\">\n                    Try Live Demo\n                    <ArrowRight className=\"w-4 h-4 group-hover:translate-x-1 transition-transform\" />\n                  </span>\n                </a>\n\n                <a\n                  href=\"https://github.com/ali-master/rule-engine\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                  className=\"group inline-flex items-center gap-2 px-8 py-4 border border-gray-700 rounded-xl font-semibold text-gray-300 hover:text-white hover:border-gray-600 transition-all duration-300\"\n                >\n                  <Github className=\"w-5 h-5\" />\n                  View on GitHub\n                  <ExternalLink className=\"w-4 h-4 opacity-50 group-hover:opacity-100 transition-opacity\" />\n                </a>\n              </div>\n\n              {/* Stats */}\n              <div className=\"flex items-center justify-center gap-8 sm:gap-12 pt-12\">\n                <div className=\"text-center\">\n                  <div className=\"text-3xl sm:text-4xl font-bold text-white\">\n                    {stats.loading ? (\n                      <div className=\"animate-pulse bg-gray-700 h-10 w-16 rounded mx-auto\"></div>\n                    ) : (\n                      stats.downloads\n                    )}\n                  </div>\n                  <div className=\"text-sm text-gray-400\">Downloads</div>\n                </div>\n                <div className=\"text-center\">\n                  <div className=\"text-3xl sm:text-4xl font-bold text-white\">\n                    {stats.loading ? (\n                      <div className=\"animate-pulse bg-gray-700 h-10 w-16 rounded mx-auto\"></div>\n                    ) : (\n                      stats.contributors\n                    )}\n                  </div>\n                  <div className=\"text-sm text-gray-400\">Contributors</div>\n                </div>\n                <div className=\"text-center\">\n                  <div className=\"text-3xl sm:text-4xl font-bold text-white\">\n                    {stats.loading ? (\n                      <div className=\"animate-pulse bg-gray-700 h-10 w-16 rounded mx-auto\"></div>\n                    ) : (\n                      stats.stars\n                    )}\n                  </div>\n                  <div className=\"text-sm text-gray-400\">GitHub Rating</div>\n                </div>\n              </div>\n            </div>\n\n            {/* Scroll indicator */}\n            <div className=\"absolute bottom-10 left-1/2 -translate-x-1/2 animate-bounce\">\n              <ChevronRight className=\"w-6 h-6 text-gray-400 rotate-90\" />\n            </div>\n          </div>\n        </section>\n\n        {/* Features Section */}\n        <section id=\"features\" className=\"py-20 sm:py-32 px-4 sm:px-6 lg:px-8\">\n          <div className=\"max-w-7xl mx-auto\">\n            <div className=\"text-center mb-16\">\n              <h2 className=\"text-3xl sm:text-4xl lg:text-5xl font-bold text-white mb-4\">\n                Powerful Features\n              </h2>\n              <p className=\"text-lg text-gray-400 max-w-2xl mx-auto\">\n                Everything you need to build, test, and deploy business rules at\n                scale\n              </p>\n            </div>\n\n            {/* Feature Grid */}\n            <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8\">\n              {/* Feature 1 */}\n              <div className=\"group relative\">\n                <div className=\"absolute inset-0 bg-gradient-to-r from-cyan-500/20 to-blue-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500\" />\n                <div className=\"relative bg-gray-900/50 border border-gray-800 rounded-2xl p-8 hover:border-gray-700 transition-all duration-300\">\n                  <div className=\"w-12 h-12 bg-gradient-to-r from-cyan-500 to-blue-500 rounded-xl flex items-center justify-center mb-6\">\n                    <Layers className=\"w-6 h-6 text-white\" />\n                  </div>\n                  <h3 className=\"text-xl font-semibold text-white mb-3\">\n                    Visual Rule Builder\n                  </h3>\n                  <p className=\"text-gray-400\">\n                    Drag-and-drop interface to create complex rules without\n                    writing code. Perfect for business users and developers\n                    alike.\n                  </p>\n                </div>\n              </div>\n\n              {/* Feature 2 */}\n              <div className=\"group relative\">\n                <div className=\"absolute inset-0 bg-gradient-to-r from-purple-500/20 to-pink-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500\" />\n                <div className=\"relative bg-gray-900/50 border border-gray-800 rounded-2xl p-8 hover:border-gray-700 transition-all duration-300\">\n                  <div className=\"w-12 h-12 bg-gradient-to-r from-purple-500 to-pink-500 rounded-xl flex items-center justify-center mb-6\">\n                    <Zap className=\"w-6 h-6 text-white\" />\n                  </div>\n                  <h3 className=\"text-xl font-semibold text-white mb-3\">\n                    Real-time Evaluation\n                  </h3>\n                  <p className=\"text-gray-400\">\n                    Test your rules instantly with live data. See results update\n                    in real-time as you modify conditions.\n                  </p>\n                </div>\n              </div>\n\n              {/* Feature 3 */}\n              <div className=\"group relative\">\n                <div className=\"absolute inset-0 bg-gradient-to-r from-green-500/20 to-emerald-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500\" />\n                <div className=\"relative bg-gray-900/50 border border-gray-800 rounded-2xl p-8 hover:border-gray-700 transition-all duration-300\">\n                  <div className=\"w-12 h-12 bg-gradient-to-r from-green-500 to-emerald-500 rounded-xl flex items-center justify-center mb-6\">\n                    <Shield className=\"w-6 h-6 text-white\" />\n                  </div>\n                  <h3 className=\"text-xl font-semibold text-white mb-3\">\n                    Type-Safe\n                  </h3>\n                  <p className=\"text-gray-400\">\n                    Built with TypeScript for maximum type safety. Get\n                    autocomplete and catch errors before runtime.\n                  </p>\n                </div>\n              </div>\n\n              {/* Feature 4 */}\n              <div className=\"group relative\">\n                <div className=\"absolute inset-0 bg-gradient-to-r from-orange-500/20 to-red-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500\" />\n                <div className=\"relative bg-gray-900/50 border border-gray-800 rounded-2xl p-8 hover:border-gray-700 transition-all duration-300\">\n                  <div className=\"w-12 h-12 bg-gradient-to-r from-orange-500 to-red-500 rounded-xl flex items-center justify-center mb-6\">\n                    <Code2 className=\"w-6 h-6 text-white\" />\n                  </div>\n                  <h3 className=\"text-xl font-semibold text-white mb-3\">\n                    JSON Export\n                  </h3>\n                  <p className=\"text-gray-400\">\n                    Export rules as clean JSON for easy storage and version\n                    control. Import existing rules with one click.\n                  </p>\n                </div>\n              </div>\n\n              {/* Feature 5 */}\n              <div className=\"group relative\">\n                <div className=\"absolute inset-0 bg-gradient-to-r from-blue-500/20 to-indigo-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500\" />\n                <div className=\"relative bg-gray-900/50 border border-gray-800 rounded-2xl p-8 hover:border-gray-700 transition-all duration-300\">\n                  <div className=\"w-12 h-12 bg-gradient-to-r from-blue-500 to-indigo-500 rounded-xl flex items-center justify-center mb-6\">\n                    <Smartphone className=\"w-6 h-6 text-white\" />\n                  </div>\n                  <h3 className=\"text-xl font-semibold text-white mb-3\">\n                    Mobile Responsive\n                  </h3>\n                  <p className=\"text-gray-400\">\n                    Fully responsive design that works seamlessly on all\n                    devices. Build rules on the go.\n                  </p>\n                </div>\n              </div>\n\n              {/* Feature 6 */}\n              <div className=\"group relative\">\n                <div className=\"absolute inset-0 bg-gradient-to-r from-teal-500/20 to-cyan-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500\" />\n                <div className=\"relative bg-gray-900/50 border border-gray-800 rounded-2xl p-8 hover:border-gray-700 transition-all duration-300\">\n                  <div className=\"w-12 h-12 bg-gradient-to-r from-teal-500 to-cyan-500 rounded-xl flex items-center justify-center mb-6\">\n                    <Moon className=\"w-6 h-6 text-white\" />\n                  </div>\n                  <h3 className=\"text-xl font-semibold text-white mb-3\">\n                    Dark Mode\n                  </h3>\n                  <p className=\"text-gray-400\">\n                    Beautiful dark mode design that's easy on the eyes. Perfect\n                    for long coding sessions.\n                  </p>\n                </div>\n              </div>\n            </div>\n          </div>\n        </section>\n\n        {/* Code Examples Section */}\n        <section className=\"py-20 px-4 sm:px-6 lg:px-8 bg-gray-900/30\">\n          <div className=\"max-w-7xl mx-auto\">\n            <div className=\"text-center mb-16\">\n              <h2 className=\"text-3xl sm:text-4xl font-bold text-white mb-4\">\n                See It In Action\n              </h2>\n              <p className=\"text-lg text-gray-400\">\n                JSON-based rules that are both powerful and readable\n              </p>\n            </div>\n\n            <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-8\">\n              {/* Example 1 */}\n              <div className=\"group\">\n                <div className=\"bg-gray-900/60 border border-gray-800 rounded-xl overflow-hidden hover:border-gray-700 transition-colors\">\n                  <div className=\"bg-gradient-to-r from-cyan-500/10 to-blue-500/10 px-6 py-4 border-b border-gray-800\">\n                    <h3 className=\"text-lg font-semibold text-white flex items-center gap-2\">\n                      <Code2 className=\"w-5 h-5 text-cyan-400\" />\n                      Simple AND Rule\n                    </h3>\n                  </div>\n                  <pre className=\"p-6 text-sm overflow-x-auto\">\n                    <code className=\"text-gray-300\">\n                      {JSON.stringify(\n                        {\n                          conditions: {\n                            and: [\n                              {\n                                field: \"user.age\",\n                                operator: \"greater_than\",\n                                value: 18,\n                              },\n                              {\n                                field: \"user.status\",\n                                operator: \"equals\",\n                                value: \"active\",\n                              },\n                            ],\n                          },\n                        },\n                        null,\n                        2,\n                      )}\n                    </code>\n                  </pre>\n                  <div className=\"px-6 py-4 bg-gray-800/50 border-t border-gray-800\">\n                    <p className=\"text-sm text-gray-400\">\n                      Check if user is over 18 AND has active status\n                    </p>\n                  </div>\n                </div>\n              </div>\n\n              {/* Example 2 */}\n              <div className=\"group\">\n                <div className=\"bg-gray-900/60 border border-gray-800 rounded-xl overflow-hidden hover:border-gray-700 transition-colors\">\n                  <div className=\"bg-gradient-to-r from-purple-500/10 to-pink-500/10 px-6 py-4 border-b border-gray-800\">\n                    <h3 className=\"text-lg font-semibold text-white flex items-center gap-2\">\n                      <Code2 className=\"w-5 h-5 text-purple-400\" />\n                      Nested Conditions\n                    </h3>\n                  </div>\n                  <pre className=\"p-6 text-sm overflow-x-auto\">\n                    <code className=\"text-gray-300\">\n                      {JSON.stringify(\n                        {\n                          conditions: {\n                            and: [\n                              {\n                                field: \"user.role\",\n                                operator: \"equals\",\n                                value: \"admin\",\n                              },\n                              {\n                                or: [\n                                  {\n                                    field: \"user.department\",\n                                    operator: \"equals\",\n                                    value: \"IT\",\n                                  },\n                                  {\n                                    field: \"user.department\",\n                                    operator: \"equals\",\n                                    value: \"Security\",\n                                  },\n                                ],\n                              },\n                            ],\n                          },\n                        },\n                        null,\n                        2,\n                      )}\n                    </code>\n                  </pre>\n                  <div className=\"px-6 py-4 bg-gray-800/50 border-t border-gray-800\">\n                    <p className=\"text-sm text-gray-400\">\n                      Admin users from IT OR Security departments\n                    </p>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        </section>\n\n        {/* Demo Section */}\n        <section id=\"demo\" className=\"py-20 sm:py-32 px-4 sm:px-6 lg:px-8\">\n          <div className=\"max-w-7xl mx-auto\">\n            <div className=\"text-center mb-16\">\n              <h2 className=\"text-3xl sm:text-4xl lg:text-5xl font-bold text-white mb-4\">\n                Interactive Demo\n              </h2>\n              <p className=\"text-lg text-gray-400 max-w-2xl mx-auto\">\n                Try the Rule Builder yourself. Create, test, and export rules in\n                real-time.\n              </p>\n            </div>\n\n            {/* Demo Mode Selector */}\n            <div className=\"flex justify-center mb-8\">\n              <div className=\"inline-flex bg-gray-900/50 border border-gray-800 rounded-xl p-1\">\n                <button\n                  type=\"button\"\n                  onClick={() => setMode(\"builder\")}\n                  className={`px-6 py-3 rounded-lg text-sm font-medium transition-all duration-200 ${\n                    mode === \"builder\"\n                      ? \"bg-gradient-to-r from-cyan-500 to-blue-500 text-white shadow-lg\"\n                      : \"text-gray-400 hover:text-white hover:bg-gray-800/50\"\n                  }`}\n                >\n                  Rule Builder\n                </button>\n                <button\n                  type=\"button\"\n                  onClick={() => setMode(\"debug\")}\n                  className={`px-6 py-3 rounded-lg text-sm font-medium transition-all duration-200 ${\n                    mode === \"debug\"\n                      ? \"bg-gradient-to-r from-cyan-500 to-blue-500 text-white shadow-lg\"\n                      : \"text-gray-400 hover:text-white hover:bg-gray-800/50\"\n                  }`}\n                >\n                  Debug Test\n                </button>\n                <button\n                  type=\"button\"\n                  onClick={() => setMode(\"store-debug\")}\n                  className={`px-6 py-3 rounded-lg text-sm font-medium transition-all duration-200 ${\n                    mode === \"store-debug\"\n                      ? \"bg-gradient-to-r from-cyan-500 to-blue-500 text-white shadow-lg\"\n                      : \"text-gray-400 hover:text-white hover:bg-gray-800/50\"\n                  }`}\n                >\n                  Store Debug\n                </button>\n              </div>\n            </div>\n\n            {/* Demo Container */}\n            <div className=\"relative\">\n              {/* Glow effect */}\n              <div className=\"absolute -inset-0.5 bg-gradient-to-r from-cyan-500 to-blue-500 rounded-2xl blur opacity-20 group-hover:opacity-30 transition duration-1000\"></div>\n\n              {/* Demo Content */}\n              <div className=\"relative bg-gray-900/90 backdrop-blur-xl border border-gray-800 rounded-2xl overflow-hidden\">\n                <div className=\"bg-gradient-to-r from-gray-800/50 to-gray-900/50 px-6 py-4 border-b border-gray-800\">\n                  <div className=\"flex items-center gap-3\">\n                    <div className=\"flex gap-1.5\">\n                      <div className=\"w-3 h-3 bg-red-500 rounded-full\"></div>\n                      <div className=\"w-3 h-3 bg-yellow-500 rounded-full\"></div>\n                      <div className=\"w-3 h-3 bg-green-500 rounded-full\"></div>\n                    </div>\n                    <div className=\"flex-1 text-center\">\n                      <span className=\"text-sm text-gray-400\">\n                        {mode === \"builder\"\n                          ? \"Rule Builder\"\n                          : mode === \"debug\"\n                            ? \"Debug Test\"\n                            : \"Store Debug\"}\n                      </span>\n                    </div>\n                  </div>\n                </div>\n\n                <div className=\"p-6 sm:p-8 lg:p-10\">\n                  {mode === \"debug\" ? (\n                    <DebugTest />\n                  ) : mode === \"store-debug\" ? (\n                    <StoreDebugTest />\n                  ) : (\n                    <RuleBuilder\n                      fields={ecommerceFields}\n                      operators={operatorConfigs}\n                      onRuleChange={(rule) =>\n                        console.log(\"Rule changed:\", rule)\n                      }\n                    />\n                  )}\n                </div>\n              </div>\n            </div>\n          </div>\n        </section>\n      </main>\n\n      {/* Modern Footer */}\n      <footer className=\"relative z-10 bg-black border-t border-gray-800\">\n        <div className=\"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 sm:py-20\">\n          {/* Top Section */}\n          <div className=\"grid grid-cols-1 lg:grid-cols-4 gap-12 lg:gap-8\">\n            {/* Brand */}\n            <div className=\"lg:col-span-2\">\n              <div className=\"flex items-center gap-3 mb-6\">\n                <div className=\"relative\">\n                  <div className=\"absolute inset-0 bg-gradient-to-r from-cyan-500 to-blue-500 rounded-xl blur-lg opacity-75\" />\n                  <div className=\"relative bg-gradient-to-r from-cyan-500 to-blue-500 p-2.5 rounded-xl\">\n                    <Layers className=\"w-6 h-6 text-white\" />\n                  </div>\n                </div>\n                <div>\n                  <h3 className=\"text-xl font-bold text-white\">Rule Engine</h3>\n                  <p className=\"text-sm text-gray-400\">Visual Logic Designer</p>\n                </div>\n              </div>\n              <p className=\"text-gray-400 mb-6 max-w-md\">\n                The ultimate JSON-based rule engine that transforms complex\n                business logic into maintainable, declarative configurations.\n                Built for modern applications.\n              </p>\n              <div className=\"flex gap-4\">\n                <a\n                  href=\"https://github.com/ali-master/rule-engine\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                  className=\"p-2 bg-gray-800 hover:bg-gray-700 rounded-lg transition-colors\"\n                >\n                  <Github className=\"w-5 h-5 text-gray-300\" />\n                </a>\n                <a\n                  href=\"#\"\n                  className=\"p-2 bg-gray-800 hover:bg-gray-700 rounded-lg transition-colors\"\n                >\n                  <Star className=\"w-5 h-5 text-gray-300\" />\n                </a>\n              </div>\n            </div>\n\n            {/* Links */}\n            <div>\n              <h4 className=\"font-semibold text-white mb-4\">Resources</h4>\n              <ul className=\"space-y-3\">\n                <li>\n                  <a\n                    href=\"https://github.com/ali-master/rule-engine#readme\"\n                    target=\"_blank\"\n                    rel=\"noopener noreferrer\"\n                    className=\"text-gray-400 hover:text-white transition-colors inline-flex items-center gap-1\"\n                  >\n                    Documentation\n                    <ExternalLink className=\"w-3 h-3\" />\n                  </a>\n                </li>\n                <li>\n                  <a\n                    href=\"https://github.com/ali-master/rule-engine/blob/master/CHANGELOG.md\"\n                    target=\"_blank\"\n                    rel=\"noopener noreferrer\"\n                    className=\"text-gray-400 hover:text-white transition-colors inline-flex items-center gap-1\"\n                  >\n                    Changelog\n                    <ExternalLink className=\"w-3 h-3\" />\n                  </a>\n                </li>\n                <li>\n                  <a\n                    href=\"#\"\n                    className=\"text-gray-400 hover:text-white transition-colors\"\n                  >\n                    API Reference\n                  </a>\n                </li>\n                <li>\n                  <a\n                    href=\"#\"\n                    className=\"text-gray-400 hover:text-white transition-colors\"\n                  >\n                    Examples\n                  </a>\n                </li>\n              </ul>\n            </div>\n\n            {/* Community */}\n            <div>\n              <h4 className=\"font-semibold text-white mb-4\">Community</h4>\n              <ul className=\"space-y-3\">\n                <li>\n                  <a\n                    href=\"https://github.com/ali-master/rule-engine/issues\"\n                    target=\"_blank\"\n                    rel=\"noopener noreferrer\"\n                    className=\"text-gray-400 hover:text-white transition-colors inline-flex items-center gap-1\"\n                  >\n                    GitHub Issues\n                    <ExternalLink className=\"w-3 h-3\" />\n                  </a>\n                </li>\n                <li>\n                  <a\n                    href=\"https://github.com/ali-master/rule-engine/discussions\"\n                    target=\"_blank\"\n                    rel=\"noopener noreferrer\"\n                    className=\"text-gray-400 hover:text-white transition-colors inline-flex items-center gap-1\"\n                  >\n                    Discussions\n                    <ExternalLink className=\"w-3 h-3\" />\n                  </a>\n                </li>\n                <li>\n                  <a\n                    href=\"https://github.com/ali-master/rule-engine/fork\"\n                    target=\"_blank\"\n                    rel=\"noopener noreferrer\"\n                    className=\"text-gray-400 hover:text-white transition-colors inline-flex items-center gap-1\"\n                  >\n                    Fork Project\n                    <GitFork className=\"w-3 h-3\" />\n                  </a>\n                </li>\n                <li>\n                  <a\n                    href=\"https://github.com/ali-master\"\n                    target=\"_blank\"\n                    rel=\"noopener noreferrer\"\n                    className=\"text-gray-400 hover:text-white transition-colors inline-flex items-center gap-1\"\n                  >\n                    Follow @ali-master\n                    <ExternalLink className=\"w-3 h-3\" />\n                  </a>\n                </li>\n              </ul>\n            </div>\n          </div>\n\n          {/* Bottom Section */}\n          <div className=\"border-t border-gray-800 mt-12 pt-8 flex flex-col sm:flex-row justify-between items-center gap-4\">\n            <p className=\"text-gray-400 text-sm text-center sm:text-left\">\n              © 2025{\" \"}\n              <a\n                href=\"https://github.com/ali-master\"\n                target=\"_blank\"\n                rel=\"noopener noreferrer\"\n                className=\"text-white hover:text-gray-300 transition-colors\"\n              >\n                Ali Torki\n              </a>\n              . MIT License.\n            </p>\n\n            <div className=\"flex items-center gap-6 text-sm text-gray-400\">\n              <a href=\"#\" className=\"hover:text-white transition-colors\">\n                Privacy\n              </a>\n              <a href=\"#\" className=\"hover:text-white transition-colors\">\n                Terms\n              </a>\n              <a href=\"#\" className=\"hover:text-white transition-colors\">\n                Cookies\n              </a>\n            </div>\n          </div>\n        </div>\n      </footer>\n    </div>\n  );\n}\n\ncreateRoot(document.getElementById(\"root\")!).render(\n  <StrictMode>\n    <Analytics />\n    <SpeedInsights />\n    <DemoApp />\n  </StrictMode>,\n);\n"
  },
  {
    "path": "packages/builder/src/hooks/use-field-discovery.ts",
    "content": "import { useState, useEffect, useCallback } from \"react\";\nimport type { FieldConfig } from \"../types\";\n\ninterface UseFieldDiscoveryOptions {\n  sampleData?: Record<string, any>;\n  maxDepth?: number;\n  includeArrayIndices?: boolean;\n  customFields?: FieldConfig[];\n}\n\nexport function useFieldDiscovery(options: UseFieldDiscoveryOptions = {}) {\n  const {\n    sampleData = {},\n    maxDepth = 5,\n    includeArrayIndices = false,\n    customFields = [],\n  } = options;\n\n  const [discoveredFields, setDiscoveredFields] = useState<FieldConfig[]>([]);\n  const [isDiscovering, setIsDiscovering] = useState(false);\n\n  const getFieldType = (value: any): FieldConfig[\"type\"] => {\n    if (value === null || value === undefined) return \"string\";\n    if (typeof value === \"string\") return \"string\";\n    if (typeof value === \"number\") return \"number\";\n    if (typeof value === \"boolean\") return \"boolean\";\n    if (value instanceof Date) return \"date\";\n    if (Array.isArray(value)) return \"array\";\n    if (typeof value === \"object\") return \"object\";\n    return \"string\";\n  };\n\n  const discoverFields = useCallback(\n    (\n      obj: any,\n      prefix = \"\",\n      depth = 0,\n      discovered: Map<string, FieldConfig> = new Map(),\n    ): Map<string, FieldConfig> => {\n      if (depth > maxDepth) return discovered;\n\n      Object.entries(obj).forEach(([key, value]) => {\n        const fieldPath = prefix ? `${prefix}.${key}` : key;\n        const jsonPath = `$.${fieldPath}`;\n\n        // Skip if already discovered\n        if (discovered.has(fieldPath)) return;\n\n        const fieldType = getFieldType(value);\n        const fieldConfig: FieldConfig = {\n          name: fieldPath,\n          label:\n            key.charAt(0).toUpperCase() +\n            key\n              .slice(1)\n              .replace(/([A-Z])/g, \" $1\")\n              .trim(),\n          type: fieldType,\n          jsonPath: true,\n          group: prefix ? prefix.split(\".\")[0] : \"Root\",\n          description: `Field at path: ${jsonPath}`,\n        };\n\n        discovered.set(fieldPath, fieldConfig);\n\n        // Recursively discover nested fields\n        if (fieldType === \"object\" && value !== null) {\n          discoverFields(\n            value as Record<string, any>,\n            fieldPath,\n            depth + 1,\n            discovered,\n          );\n        } else if (\n          fieldType === \"array\" &&\n          Array.isArray(value) &&\n          value.length > 0\n        ) {\n          // Discover fields from first array item\n          const firstItem = value[0];\n          if (typeof firstItem === \"object\" && firstItem !== null) {\n            if (includeArrayIndices) {\n              // Include specific array indices\n              (value as any[]).forEach((item: any, index: number) => {\n                if (typeof item === \"object\" && item !== null) {\n                  discoverFields(\n                    item,\n                    `${fieldPath}[${index}]`,\n                    depth + 1,\n                    discovered,\n                  );\n                }\n              });\n            } else {\n              // Use wildcard for arrays\n              discoverFields(\n                firstItem,\n                `${fieldPath}[*]`,\n                depth + 1,\n                discovered,\n              );\n            }\n          }\n        }\n      });\n\n      return discovered;\n    },\n    [maxDepth, includeArrayIndices],\n  );\n\n  const discoverFromData = useCallback(\n    (data: any) => {\n      if (!data || typeof data !== \"object\") return;\n\n      setIsDiscovering(true);\n      try {\n        const discovered = discoverFields(data);\n        const fields = Array.from(discovered.values());\n\n        // Add common JSONPath expressions\n        const commonPaths: FieldConfig[] = [\n          {\n            name: \"$\",\n            label: \"Root Object\",\n            type: \"object\",\n            jsonPath: true,\n            group: \"JSONPath\",\n            description: \"The entire data object\",\n          },\n          {\n            name: \"$..*\",\n            label: \"All Fields (Recursive)\",\n            type: \"array\",\n            jsonPath: true,\n            group: \"JSONPath\",\n            description: \"All fields at any depth\",\n          },\n        ];\n\n        // Merge with custom fields\n        const allFields = [...commonPaths, ...fields, ...customFields];\n\n        // Remove duplicates by name\n        const uniqueFields = Array.from(\n          new Map(allFields.map((field) => [field.name, field])).values(),\n        );\n\n        setDiscoveredFields(uniqueFields);\n      } finally {\n        setIsDiscovering(false);\n      }\n    },\n    [discoverFields, customFields],\n  );\n\n  // Auto-discover from sample data\n  useEffect(() => {\n    if (!sampleData || typeof sampleData !== \"object\") return;\n\n    // Use a timeout to avoid synchronous state updates\n    const timeoutId = setTimeout(() => {\n      discoverFromData(sampleData);\n    }, 0);\n\n    return () => clearTimeout(timeoutId);\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, []); // Run only once on mount\n\n  // Get suggested fields based on input\n  const getSuggestedFields = useCallback(\n    (input: string): FieldConfig[] => {\n      if (!input) return discoveredFields;\n\n      const inputLower = input.toLowerCase();\n\n      // If input looks like JSONPath, suggest JSONPath completions\n      if (input.startsWith(\"$\")) {\n        const pathSuggestions: FieldConfig[] = [];\n\n        // Extract the partial path\n        const partialPath = input.substring(2); // Remove $. prefix\n\n        discoveredFields.forEach((field) => {\n          if (field.name.toLowerCase().includes(partialPath.toLowerCase())) {\n            pathSuggestions.push({\n              ...field,\n              name: `$.${field.name}`,\n              label: `$.${field.name}`,\n            });\n          }\n        });\n\n        // Add recursive descent suggestions\n        if (partialPath.includes(\".\")) {\n          const lastPart = partialPath.split(\".\").pop() || \"\";\n          pathSuggestions.push({\n            name: `$..${lastPart}`,\n            label: `All \"${lastPart}\" fields (recursive)`,\n            type: \"array\",\n            jsonPath: true,\n            group: \"JSONPath\",\n            description: \"Search for this field at any depth\",\n          });\n        }\n\n        return pathSuggestions;\n      }\n\n      // Regular field search\n      return discoveredFields.filter(\n        (field) =>\n          field.name.toLowerCase().includes(inputLower) ||\n          field.label?.toLowerCase().includes(inputLower) ||\n          field.group?.toLowerCase().includes(inputLower),\n      );\n    },\n    [discoveredFields],\n  );\n\n  // Validate JSONPath expression\n  const validateJsonPath = useCallback(\n    (path: string): { valid: boolean; error?: string } => {\n      try {\n        // Basic JSONPath validation\n        if (!path.startsWith(\"$\")) {\n          return { valid: false, error: \"JSONPath must start with $\" };\n        }\n\n        // Check for valid JSONPath syntax\n        const validPatterns = [\n          /^\\$$/, // Root\n          /^\\$\\.[a-z_]\\w*$/i, // Simple property\n          /^\\$\\.\\w+(\\.\\w+)*$/, // Nested properties\n          /^\\$\\.\\w+\\[\\d+\\]$/, // Array index\n          /^\\$\\.\\w+\\[\\*\\]$/, // Array wildcard\n          /^\\$\\.\\.\\w+$/, // Recursive descent\n          /^\\$\\.\\w+\\[([?@])[^\\]]+\\]$/, // Filter expression\n        ];\n\n        const isValid = validPatterns.some((pattern) => pattern.test(path));\n\n        if (!isValid && path.length > 2) {\n          return { valid: false, error: \"Invalid JSONPath syntax\" };\n        }\n\n        return { valid: true };\n      } catch {\n        return { valid: false, error: \"Invalid JSONPath expression\" };\n      }\n    },\n    [],\n  );\n\n  return {\n    fields: discoveredFields,\n    isDiscovering,\n    discoverFromData,\n    getSuggestedFields,\n    validateJsonPath,\n  };\n}\n"
  },
  {
    "path": "packages/builder/src/hooks/use-keyboard-shortcuts.ts",
    "content": "import { useEffect, useCallback } from \"react\";\n\ninterface ShortcutConfig {\n  key: string;\n  ctrl?: boolean;\n  cmd?: boolean;\n  shift?: boolean;\n  alt?: boolean;\n  handler: () => void;\n  description?: string;\n}\n\nexport const useKeyboardShortcuts = (shortcuts: ShortcutConfig[]) => {\n  const handleKeyDown = useCallback(\n    (event: KeyboardEvent) => {\n      for (const shortcut of shortcuts) {\n        // Check modifier keys\n        const ctrlOrCmd = shortcut.ctrl || shortcut.cmd;\n        const isCtrlOrCmdPressed = ctrlOrCmd\n          ? event.ctrlKey || event.metaKey\n          : !(event.ctrlKey || event.metaKey);\n        const isShiftPressed = shortcut.shift\n          ? event.shiftKey\n          : !event.shiftKey;\n        const isAltPressed = shortcut.alt ? event.altKey : !event.altKey;\n\n        if (\n          event.key.toLowerCase() === shortcut.key.toLowerCase() &&\n          isCtrlOrCmdPressed &&\n          isShiftPressed &&\n          isAltPressed\n        ) {\n          event.preventDefault();\n          shortcut.handler();\n          break;\n        }\n      }\n    },\n    [shortcuts],\n  );\n\n  useEffect(() => {\n    window.addEventListener(\"keydown\", handleKeyDown);\n    return () => window.removeEventListener(\"keydown\", handleKeyDown);\n  }, [handleKeyDown]);\n\n  return shortcuts;\n};\n\n// Common shortcuts\nexport const commonShortcuts = {\n  undo: { key: \"z\", ctrl: true },\n  redo: { key: \"y\", ctrl: true },\n  redoAlt: { key: \"z\", ctrl: true, shift: true },\n  save: { key: \"s\", ctrl: true },\n  expandAll: { key: \"e\", ctrl: true, shift: true },\n  collapseAll: { key: \"c\", ctrl: true, shift: true },\n  addRule: { key: \"r\", ctrl: true },\n  addGroup: { key: \"g\", ctrl: true },\n  delete: { key: \"Delete\" },\n  duplicate: { key: \"d\", ctrl: true },\n  help: { key: \"?\", shift: true },\n  search: { key: \"f\", ctrl: true },\n  test: { key: \"t\", ctrl: true },\n};\n"
  },
  {
    "path": "packages/builder/src/hooks/use-theme.ts",
    "content": "import { useState, useEffect } from \"react\";\n\ntype Theme = \"light\" | \"dark\" | \"system\";\n\nexport function useTheme() {\n  const [theme, setTheme] = useState<Theme>(() => {\n    if (typeof window !== \"undefined\") {\n      const stored = localStorage.getItem(\"rule-builder-theme\") as Theme;\n      return stored || \"system\";\n    }\n    return \"system\";\n  });\n\n  const [resolvedTheme, setResolvedTheme] = useState<\"light\" | \"dark\">(\"light\");\n\n  useEffect(() => {\n    const root = window.document.documentElement;\n\n    const applyTheme = (newTheme: Theme) => {\n      if (newTheme === \"system\") {\n        const systemTheme = window.matchMedia(\"(prefers-color-scheme: dark)\")\n          .matches\n          ? \"dark\"\n          : \"light\";\n        root.classList.remove(\"light\", \"dark\");\n        root.classList.add(systemTheme);\n        setResolvedTheme(systemTheme);\n      } else {\n        root.classList.remove(\"light\", \"dark\");\n        root.classList.add(newTheme);\n        setResolvedTheme(newTheme);\n      }\n    };\n\n    applyTheme(theme);\n    localStorage.setItem(\"rule-builder-theme\", theme);\n\n    // Listen for system theme changes\n    const mediaQuery = window.matchMedia(\"(prefers-color-scheme: dark)\");\n    const handleChange = () => {\n      if (theme === \"system\") {\n        applyTheme(\"system\");\n      }\n    };\n\n    mediaQuery.addEventListener(\"change\", handleChange);\n    return () => mediaQuery.removeEventListener(\"change\", handleChange);\n  }, [theme]);\n\n  return { theme, setTheme, resolvedTheme };\n}\n"
  },
  {
    "path": "packages/builder/src/index.ts",
    "content": "// Import styles\nimport \"./styles/globals.css\";\n\n// Sub-components (for advanced usage)\nexport { DiffViewer } from \"./components/DiffViewer\";\nexport { DraggableConditionGroup } from \"./components/DraggableConditionGroup\";\nexport { DynamicFieldSelector } from \"./components/DynamicFieldSelector\";\nexport { FieldSelector } from \"./components/FieldSelector\";\nexport { HistoryViewer } from \"./components/HistoryViewer\";\nexport { ArrayInput } from \"./components/inputs/ArrayInput\";\nexport { BooleanInput } from \"./components/inputs/BooleanInput\";\n\nexport { DateInput } from \"./components/inputs/DateInput\";\nexport { NumberInput } from \"./components/inputs/NumberInput\";\n// Input components\nexport { SmartValueInput } from \"./components/inputs/SmartValueInput\";\nexport { JsonViewer } from \"./components/JsonViewer\";\nexport { JsonViewer as RuleViewer } from \"./components/JsonViewer\";\nexport { ModernConstraintEditor } from \"./components/ModernConstraintEditor\";\nexport { ModernRuleBuilder } from \"./components/ModernRuleBuilder\";\nexport { OperatorSelector } from \"./components/OperatorSelector\";\n// Main components\nexport { RuleBuilder } from \"./components/rule-builder\";\nexport { RuleEvaluator } from \"./components/rule-evaluator\";\n\nexport { ThemeToggle } from \"./components/ThemeToggle\";\nexport { TreeConditionGroup } from \"./components/TreeConditionGroup\";\nexport { TreeConstraintEditor } from \"./components/TreeConstraintEditor\";\nexport { TreeRuleBuilder } from \"./components/TreeRuleBuilder\";\nexport { VisualFieldSelector } from \"./components/VisualFieldSelector\";\n\nexport { useFieldDiscovery } from \"./hooks/use-field-discovery\";\nexport { useTheme } from \"./hooks/use-theme\";\n// Stores and hooks\nexport { useEnhancedRuleStore } from \"./stores/enhanced-rule-store\";\nexport { useRuleStore } from \"./stores/rule-store\";\n\n// Types\nexport type { FieldConfig, OperatorConfig, ThemeConfig } from \"./types\";\n\nexport {\n  buildJsonPath,\n  buildPath,\n  fieldToJsonPath,\n  getAllPaths,\n  getValueByPath,\n  jsonPathToField,\n  parseJsonPath,\n  validateJsonPath,\n} from \"./utils/json-path\";\n// Utils\nexport {\n  getOperatorConfig,\n  getOperatorsByCategory,\n  getOperatorsForFieldType,\n  operatorCategories,\n  operatorConfigs,\n} from \"./utils/operators\";\n\n// Re-export from rule engine\nexport { ConditionTypes, Operators } from \"@usex/rule-engine\";\n\nexport type {\n  Condition,\n  ConditionType,\n  Constraint,\n  EngineResult,\n  OperatorsType,\n  RuleType,\n} from \"@usex/rule-engine\";\n"
  },
  {
    "path": "packages/builder/src/lib/utils.ts",
    "content": "import { clsx } from \"clsx\";\nimport type { ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n"
  },
  {
    "path": "packages/builder/src/main.tsx",
    "content": "import { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { App } from \"./App\";\n\ncreateRoot(document.getElementById(\"root\")!).render(\n  <StrictMode>\n    <App />\n  </StrictMode>,\n);\n"
  },
  {
    "path": "packages/builder/src/stores/enhanced-rule-store.ts",
    "content": "import { create } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport type { RuleType, EngineResult, Condition } from \"@usex/rule-engine\";\n\nexport interface HistoryEntry {\n  rule: RuleType;\n  timestamp: number;\n  action: string;\n  description: string;\n  changes?: {\n    before?: any;\n    after?: any;\n  };\n}\n\ninterface EnhancedRuleStore {\n  // State\n  rule: RuleType;\n  history: HistoryEntry[];\n  historyIndex: number;\n  expandedGroups: Set<string>;\n\n  // Actions\n  setRule: (rule: RuleType, action?: string, description?: string) => void;\n  updateConditions: (\n    conditions: Condition | Condition[],\n    action?: string,\n    description?: string,\n  ) => void;\n  updateDefaultResult: (result: EngineResult | undefined) => void;\n\n  // History\n  undo: () => void;\n  redo: () => void;\n  canUndo: () => boolean;\n  canRedo: () => boolean;\n  getUndoInfo: () => HistoryEntry | null;\n  getRedoInfo: () => HistoryEntry | null;\n  getHistoryInfo: () => {\n    current: number;\n    total: number;\n    entries: HistoryEntry[];\n  };\n\n  // Expand/Collapse\n  toggleGroupExpanded: (path: string) => void;\n  isGroupExpanded: (path: string) => boolean;\n  expandAll: () => void;\n  collapseAll: () => void;\n\n  // Helpers\n  addToHistory: (\n    rule: RuleType,\n    action: string,\n    description: string,\n    changes?: any,\n  ) => void;\n  clearHistory: () => void;\n}\n\nconst MAX_HISTORY = 100;\n\nexport const useEnhancedRuleStore = create<EnhancedRuleStore>()(\n  devtools(\n    (set, get) => ({\n      rule: { conditions: [] },\n      history: [\n        {\n          rule: { conditions: [] },\n          timestamp: Date.now(),\n          action: \"Initialize\",\n          description: \"Initial empty rule\",\n        },\n      ],\n      historyIndex: 0,\n      expandedGroups: new Set<string>(),\n\n      setRule: (rule, action = \"Set Rule\", description = \"Rule updated\") => {\n        const currentRule = get().rule;\n        get().addToHistory(rule, action, description, {\n          before: currentRule,\n          after: rule,\n        });\n        set({ rule });\n      },\n\n      updateConditions: (\n        conditions,\n        action = \"Update Conditions\",\n        description = \"Conditions updated\",\n      ) => {\n        const state = get();\n        const newRule = { ...state.rule, conditions };\n        const changeDescription = Array.isArray(conditions)\n          ? `Updated ${conditions.length} condition group(s)`\n          : \"Updated condition\";\n\n        state.addToHistory(newRule, action, description || changeDescription, {\n          before: state.rule.conditions,\n          after: conditions,\n        });\n        set({ rule: newRule });\n      },\n\n      updateDefaultResult: (result) => {\n        const state = get();\n        const newRule = { ...state.rule, default: result };\n        state.addToHistory(\n          newRule,\n          \"Update Default Result\",\n          result ? \"Set default result\" : \"Removed default result\",\n          { before: state.rule.default, after: result },\n        );\n        set({ rule: newRule });\n      },\n\n      undo: () => {\n        const { history, historyIndex } = get();\n        if (historyIndex > 0) {\n          const newIndex = historyIndex - 1;\n          set({\n            historyIndex: newIndex,\n            rule: history[newIndex].rule,\n          });\n        }\n      },\n\n      redo: () => {\n        const { history, historyIndex } = get();\n        if (historyIndex < history.length - 1) {\n          const newIndex = historyIndex + 1;\n          set({\n            historyIndex: newIndex,\n            rule: history[newIndex].rule,\n          });\n        }\n      },\n\n      canUndo: () => get().historyIndex > 0,\n      canRedo: () => get().historyIndex < get().history.length - 1,\n\n      getUndoInfo: () => {\n        const { history, historyIndex } = get();\n        return historyIndex > 0 ? history[historyIndex - 1] : null;\n      },\n\n      getRedoInfo: () => {\n        const { history, historyIndex } = get();\n        return historyIndex < history.length - 1\n          ? history[historyIndex + 1]\n          : null;\n      },\n\n      getHistoryInfo: () => {\n        const { history, historyIndex } = get();\n        return {\n          current: historyIndex,\n          total: history.length,\n          entries: history,\n        };\n      },\n\n      toggleGroupExpanded: (path: string) => {\n        set((state) => {\n          const newExpanded = new Set(state.expandedGroups);\n          if (newExpanded.has(path)) {\n            newExpanded.delete(path);\n          } else {\n            newExpanded.add(path);\n          }\n          return { expandedGroups: newExpanded };\n        });\n      },\n\n      isGroupExpanded: (path: string) => {\n        return get().expandedGroups.has(path);\n      },\n\n      expandAll: () => {\n        // For expandAll, we create a very large set that will match any path\n        const allPaths = new Set<string>();\n        // Add common path patterns\n        for (let i = 0; i < 10; i++) {\n          for (let j = 0; j < 10; j++) {\n            allPaths.add(`${i}`);\n            allPaths.add(`${i}-${j}`);\n            for (let k = 0; k < 10; k++) {\n              allPaths.add(`${i}-${j}-${k}`);\n            }\n          }\n        }\n        set({ expandedGroups: allPaths });\n      },\n\n      collapseAll: () => {\n        set({ expandedGroups: new Set<string>() });\n      },\n\n      addToHistory: (rule, action, description, changes) => {\n        set((state) => {\n          const newHistory = state.history.slice(0, state.historyIndex + 1);\n          newHistory.push({\n            rule: JSON.parse(JSON.stringify(rule)), // Deep clone\n            timestamp: Date.now(),\n            action,\n            description,\n            changes,\n          });\n\n          // Limit history size\n          if (newHistory.length > MAX_HISTORY) {\n            newHistory.shift();\n          }\n\n          return {\n            history: newHistory,\n            historyIndex: newHistory.length - 1,\n          };\n        });\n      },\n\n      clearHistory: () => {\n        const currentRule = get().rule;\n        set({\n          history: [\n            {\n              rule: currentRule,\n              timestamp: Date.now(),\n              action: \"Clear History\",\n              description: \"History cleared\",\n            },\n          ],\n          historyIndex: 0,\n        });\n      },\n    }),\n    {\n      name: \"rule-builder-store\",\n    },\n  ),\n);\n"
  },
  {
    "path": "packages/builder/src/stores/rule-store.ts",
    "content": "import { create } from \"zustand\";\nimport type { RuleType, EngineResult, Condition } from \"@usex/rule-engine\";\n\ninterface RuleStore {\n  // State\n  rule: RuleType;\n  history: RuleType[];\n  historyIndex: number;\n\n  // Actions\n  setRule: (rule: RuleType) => void;\n  updateConditions: (conditions: Condition | Condition[]) => void;\n  updateDefaultResult: (result: EngineResult | undefined) => void;\n\n  // History\n  undo: () => void;\n  redo: () => void;\n  canUndo: () => boolean;\n  canRedo: () => boolean;\n\n  // Helpers\n  addToHistory: (rule: RuleType) => void;\n  clearHistory: () => void;\n}\n\nconst MAX_HISTORY = 50;\n\nexport const useRuleStore = create<RuleStore>((set, get) => ({\n  rule: { conditions: [] },\n  history: [{ conditions: [] }],\n  historyIndex: 0,\n\n  setRule: (rule) => {\n    set((state) => {\n      state.addToHistory(rule);\n      return { rule };\n    });\n  },\n\n  updateConditions: (conditions) => {\n    set((state) => {\n      const newRule = { ...state.rule, conditions };\n      state.addToHistory(newRule);\n      return { rule: newRule };\n    });\n  },\n\n  updateDefaultResult: (result) => {\n    set((state) => {\n      const newRule = { ...state.rule, default: result };\n      state.addToHistory(newRule);\n      return { rule: newRule };\n    });\n  },\n\n  undo: () => {\n    const { history, historyIndex } = get();\n    if (historyIndex > 0) {\n      const newIndex = historyIndex - 1;\n      set({\n        historyIndex: newIndex,\n        rule: history[newIndex],\n      });\n    }\n  },\n\n  redo: () => {\n    const { history, historyIndex } = get();\n    if (historyIndex < history.length - 1) {\n      const newIndex = historyIndex + 1;\n      set({\n        historyIndex: newIndex,\n        rule: history[newIndex],\n      });\n    }\n  },\n\n  canUndo: () => get().historyIndex > 0,\n  canRedo: () => get().historyIndex < get().history.length - 1,\n\n  addToHistory: (rule) => {\n    set((state) => {\n      const newHistory = state.history.slice(0, state.historyIndex + 1);\n      newHistory.push(rule);\n\n      // Limit history size\n      if (newHistory.length > MAX_HISTORY) {\n        newHistory.shift();\n      }\n\n      return {\n        history: newHistory,\n        historyIndex: newHistory.length - 1,\n      };\n    });\n  },\n\n  clearHistory: () => {\n    set({\n      history: [get().rule],\n      historyIndex: 0,\n    });\n  },\n}));\n"
  },
  {
    "path": "packages/builder/src/stores/unified-rule-store.ts",
    "content": "import React from \"react\";\nimport { create } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport type {\n  RuleType,\n  EngineResult,\n  Constraint,\n  ConditionType,\n  Condition,\n} from \"@usex/rule-engine\";\n\nexport interface HistoryEntry {\n  rule: RuleType;\n  timestamp: number;\n  action: string;\n  description: string;\n  changes?: {\n    before?: any;\n    after?: any;\n  };\n}\n\nexport interface ValidationError {\n  path: string;\n  message: string;\n}\n\ninterface UnifiedRuleStore {\n  // Core State\n  rule: RuleType;\n  isDirty: boolean;\n  validationErrors: ValidationError[];\n\n  // History\n  history: HistoryEntry[];\n  historyIndex: number;\n\n  // UI State\n  expandedGroups: Set<string>;\n\n  // Core Actions\n  setRule: (rule: RuleType, action?: string, description?: string) => void;\n  updateConditions: (\n    conditions: Condition | Condition[],\n    action?: string,\n    description?: string,\n  ) => void;\n  updateDefaultResult: (result: EngineResult | undefined) => void;\n  resetRule: (initialRule?: RuleType) => void;\n\n  // Condition/Constraint Management\n  addCondition: (parentPath: string, conditionType: ConditionType) => void;\n  removeCondition: (path: string) => void;\n  updateCondition: (path: string, condition: Condition) => void;\n  addConstraint: (conditionPath: string, constraint: Constraint) => void;\n  updateConstraint: (path: string, constraint: Constraint) => void;\n  removeConstraint: (path: string) => void;\n\n  // History\n  undo: () => void;\n  redo: () => void;\n  canUndo: () => boolean;\n  canRedo: () => boolean;\n  getUndoInfo: () => HistoryEntry | null;\n  getRedoInfo: () => HistoryEntry | null;\n  getHistoryInfo: () => {\n    current: number;\n    total: number;\n    entries: HistoryEntry[];\n  };\n\n  // UI State Management\n  toggleGroupExpanded: (path: string) => void;\n  isGroupExpanded: (path: string) => boolean;\n  expandAll: () => void;\n  collapseAll: () => void;\n\n  // Validation\n  validate: () => boolean;\n  clearErrors: () => void;\n\n  // Import/Export\n  importRule: (rule: RuleType) => void;\n  exportRule: () => RuleType;\n\n  // Internal Helpers\n  addToHistory: (\n    rule: RuleType,\n    action: string,\n    description: string,\n    changes?: any,\n  ) => void;\n  clearHistory: () => void;\n}\n\nconst MAX_HISTORY = 100;\nconst initialRule: RuleType = { conditions: {} };\n\n// Helper functions for path-based operations with single condition object\n// Forward declare to handle mutual recursion\nlet updateItemsAtPath: (\n  items: (Condition | Constraint)[],\n  pathParts: string[],\n  updater: (items: (Condition | Constraint)[]) => (Condition | Constraint)[],\n) => (Condition | Constraint)[];\n\nconst updateConditionAtPath = (\n  condition: Condition,\n  pathParts: string[],\n  updater: (items: (Condition | Constraint)[]) => (Condition | Constraint)[],\n): Condition => {\n  if (pathParts.length === 0) {\n    return condition;\n  }\n\n  const [currentPart, ...remainingParts] = pathParts;\n  const newCondition = { ...condition };\n\n  // Handle condition type parts (e.g., \"and\", \"or\", \"none\")\n  if (currentPart === \"and\" && condition.and) {\n    if (remainingParts.length === 0) {\n      newCondition.and = updater(condition.and);\n    } else {\n      newCondition.and = updateItemsAtPath(\n        condition.and,\n        remainingParts,\n        updater,\n      );\n    }\n  } else if (currentPart === \"or\" && condition.or) {\n    if (remainingParts.length === 0) {\n      newCondition.or = updater(condition.or);\n    } else {\n      newCondition.or = updateItemsAtPath(\n        condition.or,\n        remainingParts,\n        updater,\n      );\n    }\n  } else if (currentPart === \"none\" && condition.none) {\n    if (remainingParts.length === 0) {\n      newCondition.none = updater(condition.none);\n    } else {\n      newCondition.none = updateItemsAtPath(\n        condition.none,\n        remainingParts,\n        updater,\n      );\n    }\n  }\n\n  return newCondition;\n};\n\nupdateItemsAtPath = (\n  items: (Condition | Constraint)[],\n  pathParts: string[],\n  updater: (items: (Condition | Constraint)[]) => (Condition | Constraint)[],\n): (Condition | Constraint)[] => {\n  if (pathParts.length === 0) {\n    return updater(items);\n  }\n\n  const [currentPart, ...remainingParts] = pathParts;\n\n  // Handle numeric indices (e.g., \"0\", \"1\")\n  if (currentPart.match(/^\\d+$/)) {\n    const index = Number.parseInt(currentPart, 10);\n    if (index >= 0 && index < items.length) {\n      const newItems = [...items];\n      const item = newItems[index];\n\n      // Check if it's a condition (has and/or/none) or constraint (has field)\n      if (\"field\" in item) {\n        // It's a constraint, can't update further\n        return items;\n      } else {\n        // It's a condition, continue recursively\n        newItems[index] = updateConditionAtPath(\n          item as Condition,\n          remainingParts,\n          updater,\n        );\n      }\n      return newItems;\n    }\n  }\n\n  return items;\n};\n\nexport const useUnifiedRuleStore = create<UnifiedRuleStore>()(\n  devtools(\n    (set, get) => ({\n      // Initial State\n      rule: initialRule,\n      isDirty: false,\n      validationErrors: [],\n      history: [\n        {\n          rule: initialRule,\n          timestamp: Date.now(),\n          action: \"Initialize\",\n          description: \"Initial empty rule\",\n        },\n      ],\n      historyIndex: 0,\n      expandedGroups: new Set<string>(),\n\n      // Core Actions\n      setRule: (rule, action = \"Set Rule\", description = \"Rule updated\") => {\n        const state = get();\n        state.addToHistory(rule, action, description, {\n          before: state.rule,\n          after: rule,\n        });\n        set({ rule, isDirty: true });\n      },\n\n      updateConditions: (\n        conditions,\n        action = \"Update Conditions\",\n        description = \"Conditions updated\",\n      ) => {\n        const state = get();\n        const newRule = { ...state.rule, conditions };\n\n        const changeDescription = Array.isArray(conditions)\n          ? `Updated ${conditions.length} condition group(s)`\n          : \"Updated condition\";\n\n        state.addToHistory(newRule, action, description || changeDescription, {\n          before: state.rule.conditions,\n          after: conditions,\n        });\n\n        set({ rule: newRule, isDirty: true });\n      },\n\n      updateDefaultResult: (result) => {\n        const state = get();\n        const newRule = { ...state.rule, default: result };\n        state.addToHistory(\n          newRule,\n          \"Update Default Result\",\n          result ? \"Set default result\" : \"Removed default result\",\n          { before: state.rule.default, after: result },\n        );\n        set({ rule: newRule, isDirty: true });\n      },\n\n      resetRule: (initialRuleData = initialRule) => {\n        set({\n          rule: initialRuleData,\n          isDirty: false,\n          validationErrors: [],\n          history: [\n            {\n              rule: initialRuleData,\n              timestamp: Date.now(),\n              action: \"Reset\",\n              description: \"Rule reset to initial state\",\n            },\n          ],\n          historyIndex: 0,\n        });\n      },\n\n      // Condition/Constraint Management\n      addCondition: (parentPath: string, conditionType: ConditionType) => {\n        const state = get();\n        const newCondition: Condition = { [conditionType]: [] };\n\n        if (!parentPath) {\n          // Add to root level - replace the entire conditions object\n          state.updateConditions(\n            newCondition,\n            \"Add Root Condition\",\n            `Set root ${conditionType} condition group`,\n          );\n          return;\n        }\n\n        const pathParts = parentPath.split(\".\");\n        const updatedConditions = updateConditionAtPath(\n          state.rule.conditions as Condition,\n          pathParts,\n          (items) => [...items, newCondition],\n        );\n\n        state.updateConditions(\n          updatedConditions,\n          \"Add Nested Condition\",\n          `Added ${conditionType} condition to ${parentPath}`,\n        );\n      },\n\n      removeCondition: (path: string) => {\n        const state = get();\n        const pathParts = path.split(\".\");\n\n        // For the new structure, we need to handle removal within the single conditions object\n        const conditionIndex = Number.parseInt(pathParts.pop() || \"0\", 10);\n        const parentPathParts = pathParts;\n\n        const updatedConditions = updateConditionAtPath(\n          state.rule.conditions as Condition,\n          parentPathParts,\n          (items) => items.filter((_, index) => index !== conditionIndex),\n        );\n\n        state.updateConditions(\n          updatedConditions,\n          \"Remove Condition\",\n          `Removed condition at ${path}`,\n        );\n      },\n\n      updateCondition: (path: string, newCondition: Condition) => {\n        const state = get();\n        const pathParts = path.split(\".\");\n\n        if (pathParts.length === 0) {\n          // Update the root condition\n          state.updateConditions(\n            newCondition,\n            \"Update Root Condition\",\n            \"Updated root condition\",\n          );\n          return;\n        }\n\n        // Update nested condition\n        const conditionIndex = Number.parseInt(pathParts.pop() || \"0\", 10);\n        const parentPathParts = pathParts;\n\n        const updatedConditions = updateConditionAtPath(\n          state.rule.conditions as Condition,\n          parentPathParts,\n          (items) => {\n            const newItems = [...items];\n            if (conditionIndex >= 0 && conditionIndex < items.length) {\n              newItems[conditionIndex] = newCondition;\n            }\n            return newItems;\n          },\n        );\n\n        state.updateConditions(\n          updatedConditions,\n          \"Update Condition\",\n          `Updated condition at ${path}`,\n        );\n      },\n\n      addConstraint: (conditionPath: string, constraint: Constraint) => {\n        const state = get();\n        const pathParts = conditionPath.split(\".\");\n\n        const updatedConditions = updateConditionAtPath(\n          state.rule.conditions as Condition,\n          pathParts,\n          (items) => [...items, constraint],\n        );\n\n        state.updateConditions(\n          updatedConditions,\n          \"Add Constraint\",\n          `Added constraint to ${conditionPath}`,\n        );\n      },\n\n      updateConstraint: (path: string, constraint: Constraint) => {\n        const state = get();\n        const pathParts = path.split(\".\");\n        const constraintIndex = Number.parseInt(pathParts.pop() || \"0\", 10);\n\n        const updatedConditions = updateConditionAtPath(\n          state.rule.conditions as Condition,\n          pathParts,\n          (items) => {\n            const newItems = [...items];\n            if (constraintIndex >= 0 && constraintIndex < items.length) {\n              newItems[constraintIndex] = constraint;\n            }\n            return newItems;\n          },\n        );\n\n        state.updateConditions(\n          updatedConditions,\n          \"Update Constraint\",\n          `Updated constraint at ${path}`,\n        );\n      },\n\n      removeConstraint: (path: string) => {\n        const state = get();\n        const pathParts = path.split(\".\");\n        const constraintIndex = Number.parseInt(pathParts.pop() || \"0\", 10);\n\n        const updatedConditions = updateConditionAtPath(\n          state.rule.conditions as Condition,\n          pathParts,\n          (items) => items.filter((_, index) => index !== constraintIndex),\n        );\n\n        state.updateConditions(\n          updatedConditions,\n          \"Remove Constraint\",\n          `Removed constraint at ${path}`,\n        );\n      },\n\n      // History Management\n      undo: () => {\n        const { history, historyIndex } = get();\n        if (historyIndex > 0) {\n          const newIndex = historyIndex - 1;\n          set({\n            historyIndex: newIndex,\n            rule: history[newIndex].rule,\n            isDirty: true,\n          });\n        }\n      },\n\n      redo: () => {\n        const { history, historyIndex } = get();\n        if (historyIndex < history.length - 1) {\n          const newIndex = historyIndex + 1;\n          set({\n            historyIndex: newIndex,\n            rule: history[newIndex].rule,\n            isDirty: true,\n          });\n        }\n      },\n\n      canUndo: () => get().historyIndex > 0,\n      canRedo: () => get().historyIndex < get().history.length - 1,\n\n      getUndoInfo: () => {\n        const { history, historyIndex } = get();\n        return historyIndex > 0 ? history[historyIndex - 1] : null;\n      },\n\n      getRedoInfo: () => {\n        const { history, historyIndex } = get();\n        return historyIndex < history.length - 1\n          ? history[historyIndex + 1]\n          : null;\n      },\n\n      getHistoryInfo: () => {\n        const { history, historyIndex } = get();\n        return {\n          current: historyIndex,\n          total: history.length,\n          entries: history,\n        };\n      },\n\n      // UI State Management\n      toggleGroupExpanded: (path: string) => {\n        set((state) => {\n          const newExpanded = new Set(state.expandedGroups);\n          if (newExpanded.has(path)) {\n            newExpanded.delete(path);\n          } else {\n            newExpanded.add(path);\n          }\n          return { expandedGroups: newExpanded };\n        });\n      },\n\n      isGroupExpanded: (path: string) => {\n        return get().expandedGroups.has(path);\n      },\n\n      expandAll: () => {\n        const allPaths = new Set<string>();\n        for (let i = 0; i < 10; i++) {\n          for (let j = 0; j < 10; j++) {\n            allPaths.add(`${i}`);\n            allPaths.add(`${i}.and`);\n            allPaths.add(`${i}.or`);\n            allPaths.add(`${i}.none`);\n            for (let k = 0; k < 10; k++) {\n              allPaths.add(`${i}.and.${j}`);\n              allPaths.add(`${i}.or.${j}`);\n              allPaths.add(`${i}.none.${j}`);\n            }\n          }\n        }\n        set({ expandedGroups: allPaths });\n      },\n\n      collapseAll: () => {\n        set({ expandedGroups: new Set<string>() });\n      },\n\n      // Validation\n      validate: () => {\n        const state = get();\n        const errors: ValidationError[] = [];\n\n        if (!state.rule.conditions) {\n          errors.push({\n            path: \"conditions\",\n            message: \"Conditions are required\",\n          });\n        } else {\n          const condition = state.rule.conditions as Condition;\n\n          // Check if conditions object is empty\n          if (Object.keys(condition).length === 0) {\n            errors.push({\n              path: \"conditions\",\n              message: \"At least one constraint or condition is required\",\n            });\n          } else {\n            const hasContent =\n              (condition.and && condition.and.length > 0) ||\n              (condition.or && condition.or.length > 0) ||\n              (condition.none && condition.none.length > 0);\n\n            if (!hasContent) {\n              errors.push({\n                path: \"conditions\",\n                message: \"At least one constraint or condition is required\",\n              });\n            }\n          }\n        }\n\n        set({ validationErrors: errors });\n        return errors.length === 0;\n      },\n\n      clearErrors: () => {\n        set({ validationErrors: [] });\n      },\n\n      // Import/Export\n      importRule: (rule: RuleType) => {\n        const state = get();\n        state.setRule(\n          rule,\n          \"Import Rule\",\n          \"Imported rule from external source\",\n        );\n      },\n\n      exportRule: () => {\n        return get().rule;\n      },\n\n      // Internal Helpers\n      addToHistory: (rule, action, description, changes) => {\n        set((state) => {\n          const newHistory = state.history.slice(0, state.historyIndex + 1);\n          newHistory.push({\n            rule: JSON.parse(JSON.stringify(rule)), // Deep clone\n            timestamp: Date.now(),\n            action,\n            description,\n            changes,\n          });\n\n          // Limit history size\n          if (newHistory.length > MAX_HISTORY) {\n            newHistory.shift();\n          }\n\n          return {\n            history: newHistory,\n            historyIndex: newHistory.length - 1,\n          };\n        });\n      },\n\n      clearHistory: () => {\n        const currentRule = get().rule;\n        set({\n          history: [\n            {\n              rule: currentRule,\n              timestamp: Date.now(),\n              action: \"Clear History\",\n              description: \"History cleared\",\n            },\n          ],\n          historyIndex: 0,\n        });\n      },\n    }),\n    {\n      name: \"unified-rule-builder-store\",\n    },\n  ),\n);\n\n// Export a simple hook that matches the old context API with proper reactivity\nexport const useRuleBuilder = () => {\n  // Get the entire store state directly to ensure reactivity\n  const store = useUnifiedRuleStore();\n\n  // Create stable state object\n  const state = React.useMemo(\n    () => ({\n      rule: store.rule,\n      isDirty: store.isDirty,\n      validationErrors: store.validationErrors,\n    }),\n    [store.rule, store.isDirty, store.validationErrors],\n  );\n\n  // Return the API object\n  return React.useMemo(\n    () => ({\n      state,\n      // Core actions\n      updateRule: store.setRule,\n      updateConditions: store.updateConditions,\n      updateDefaultResult: store.updateDefaultResult,\n      resetRule: store.resetRule,\n\n      // Condition/Constraint management\n      addCondition: store.addCondition,\n      removeCondition: store.removeCondition,\n      updateCondition: store.updateCondition,\n      addConstraint: store.addConstraint,\n      updateConstraint: store.updateConstraint,\n      removeConstraint: store.removeConstraint,\n\n      // Import/Export\n      importRule: store.importRule,\n      exportRule: store.exportRule,\n\n      // Validation\n      validate: store.validate,\n\n      // History\n      undo: store.undo,\n      redo: store.redo,\n      canUndo: store.canUndo,\n      canRedo: store.canRedo,\n    }),\n    [store, state],\n  );\n};\n"
  },
  {
    "path": "packages/builder/src/styles/animations.css",
    "content": "/* Custom animations for the demo page */\n\n@keyframes float {\n  0%, 100% {\n    transform: translateY(0px) translateX(0px);\n  }\n  33% {\n    transform: translateY(-20px) translateX(10px);\n  }\n  66% {\n    transform: translateY(10px) translateX(-10px);\n  }\n}\n\n@keyframes glow {\n  0%, 100% {\n    opacity: 0.5;\n    transform: scale(1);\n  }\n  50% {\n    opacity: 0.8;\n    transform: scale(1.05);\n  }\n}\n\n@keyframes gradient-shift {\n  0% {\n    background-position: 0% 50%;\n  }\n  50% {\n    background-position: 100% 50%;\n  }\n  100% {\n    background-position: 0% 50%;\n  }\n}\n\n/* Utility classes */\n.animate-float {\n  animation: float 6s ease-in-out infinite;\n}\n\n.animate-glow {\n  animation: glow 3s ease-in-out infinite;\n}\n\n.animate-gradient {\n  background-size: 200% 200%;\n  animation: gradient-shift 4s ease infinite;\n}\n\n.animation-delay-2000 {\n  animation-delay: 2s;\n}\n\n.animation-delay-4000 {\n  animation-delay: 4s;\n}\n\n/* Hover effects */\n.hover-lift {\n  transition: transform 0.3s ease, box-shadow 0.3s ease;\n}\n\n.hover-lift:hover {\n  transform: translateY(-4px);\n  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);\n}\n\n/* Glass morphism */\n.glass {\n  background: rgba(255, 255, 255, 0.05);\n  backdrop-filter: blur(10px);\n  -webkit-backdrop-filter: blur(10px);\n  border: 1px solid rgba(255, 255, 255, 0.1);\n}\n\n/* Gradient text animation */\n.gradient-text-animate {\n  background: linear-gradient(\n    135deg,\n    #06b6d4 0%,\n    #3b82f6 25%,\n    #8b5cf6 50%,\n    #ec4899 75%,\n    #06b6d4 100%\n  );\n  background-size: 200% 200%;\n  -webkit-background-clip: text;\n  -webkit-text-fill-color: transparent;\n  background-clip: text;\n  animation: gradient-shift 3s ease infinite;\n}"
  },
  {
    "path": "packages/builder/src/styles/globals.css",
    "content": "@import \"tailwindcss\";\n\n@custom-variant dark (&:is(.dark *));\n\n@theme inline {\n  --color-background: hsl(var(--background));\n  --color-foreground: hsl(var(--foreground));\n  --color-card: hsl(var(--card));\n  --color-card-foreground: hsl(var(--card-foreground));\n  --color-popover: hsl(var(--popover));\n  --color-popover-foreground: hsl(var(--popover-foreground));\n  --color-primary: hsl(var(--primary));\n  --color-primary-foreground: hsl(var(--primary-foreground));\n  --color-secondary: hsl(var(--secondary));\n  --color-secondary-foreground: hsl(var(--secondary-foreground));\n  --color-muted: hsl(var(--muted));\n  --color-muted-foreground: hsl(var(--muted-foreground));\n  --color-accent: hsl(var(--accent));\n  --color-accent-foreground: hsl(var(--accent-foreground));\n  --color-destructive: hsl(var(--destructive));\n  --color-destructive-foreground: hsl(var(--destructive-foreground));\n  --color-border: hsl(var(--border));\n  --color-input: hsl(var(--input));\n  --color-ring: hsl(var(--ring));\n  --radius-sm: calc(var(--radius) - 4px);\n  --radius-md: calc(var(--radius) - 2px);\n  --radius-lg: var(--radius);\n  --radius-xl: calc(var(--radius) + 4px);\n\n  /* Rule Engine Specific */\n  --color-rule-or: hsl(var(--rule-or));\n  --color-rule-or-bg: hsl(var(--rule-or-bg));\n  --color-rule-and: hsl(var(--rule-and));\n  --color-rule-and-bg: hsl(var(--rule-and-bg));\n  --color-rule-none: hsl(var(--rule-none));\n  --color-rule-none-bg: hsl(var(--rule-none-bg));\n}\n\n:root {\n  /* Colors */\n  --background: 0 0% 100%;\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary: 240 5.9% 10%;\n  --primary-foreground: 0 0% 98%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 240 5.9% 10%;\n  --radius: 0.5rem;\n\n  /* Rule Engine Specific */\n  --rule-or: 217 91% 60%;\n  --rule-or-bg: 217 91% 96%;\n  --rule-and: 142 71% 45%;\n  --rule-and-bg: 142 71% 95%;\n  --rule-none: 0 84% 60%;\n  --rule-none-bg: 0 84% 95%;\n}\n\n.dark {\n  --background: 0 0% 3.9%;\n  --foreground: 0 0% 98%;\n  --card: 0 0% 8%;\n  --card-foreground: 0 0% 98%;\n  --popover: 0 0% 8%;\n  --popover-foreground: 0 0% 98%;\n  --primary: 0 0% 98%;\n  --primary-foreground: 0 0% 9%;\n  --secondary: 0 0% 14.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 14.9%;\n  --muted-foreground: 0 0% 63.9%;\n  --accent: 0 0% 14.9%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 0 0% 14.9%;\n  --input: 0 0% 14.9%;\n  --ring: 0 0% 83.9%;\n\n  /* Rule Engine Specific */\n  --rule-or: 217 91% 60%;\n  --rule-or-bg: 217 91% 15%;\n  --rule-and: 142 71% 45%;\n  --rule-and-bg: 142 71% 15%;\n  --rule-none: 0 84% 60%;\n  --rule-none-bg: 0 84% 15%;\n}\n\n@layer base {\n  *,\n  ::after,\n  ::before,\n  ::backdrop,\n  ::file-selector-button {\n    @apply border-border;\n  }\n\n  body {\n    @apply bg-background text-foreground antialiased;\n    font-feature-settings:\n      \"rlig\" 1,\n      \"calt\" 1;\n    -webkit-font-smoothing: antialiased;\n    -moz-osx-font-smoothing: grayscale;\n    cursor: default;\n  }\n}\n\n@utility scrollbar {\n  ::-webkit-scrollbar {\n    width: 8px;\n    height: 8px;\n  }\n\n  ::-webkit-scrollbar-track {\n    @apply bg-secondary;\n  }\n\n  ::-webkit-scrollbar-thumb {\n    @apply bg-muted-foreground/30 rounded;\n  }\n\n  ::-webkit-scrollbar-thumb:hover {\n    @apply bg-muted-foreground/50;\n  }\n}\n\n@utility radix-fixes {\n  /* Fix for Radix UI popover/select backgrounds */\n  [data-radix-popper-content-wrapper] {\n    @apply z-50;\n  }\n\n  /* Select dropdown specific fixes */\n  [role=\"listbox\"] {\n    background-color: hsl(var(--popover)) !important;\n  }\n\n  [data-radix-select-content] {\n    background-color: hsl(var(--popover)) !important;\n  }\n\n  [data-radix-select-viewport] {\n    background-color: transparent !important;\n  }\n\n  [data-radix-select-item] {\n    @apply bg-transparent;\n  }\n\n  [data-radix-select-item][data-highlighted] {\n    @apply bg-accent text-accent-foreground;\n  }\n}\n\n/* Animation classes */\n@keyframes fadeIn {\n  from {\n    opacity: 0;\n    transform: translateY(10px);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n\n@keyframes slideIn {\n  from {\n    transform: translateX(-100%);\n  }\n  to {\n    transform: translateX(0);\n  }\n}\n\n@keyframes in {\n  from {\n    opacity: var(--tw-enter-opacity, 1);\n    transform: translate3d(\n        var(--tw-enter-translate-x, 0),\n        var(--tw-enter-translate-y, 0),\n        0\n      )\n      scale3d(\n        var(--tw-enter-scale, 1),\n        var(--tw-enter-scale, 1),\n        var(--tw-enter-scale, 1)\n      )\n      rotate(var(--tw-enter-rotate, 0));\n  }\n  to {\n    opacity: 1;\n    transform: translate3d(0, 0, 0) scale3d(1, 1, 1) rotate(0);\n  }\n}\n\n@keyframes out {\n  from {\n    opacity: 1;\n    transform: translate3d(0, 0, 0) scale3d(1, 1, 1) rotate(0);\n  }\n  to {\n    opacity: var(--tw-exit-opacity, 1);\n    transform: translate3d(\n        var(--tw-exit-translate-x, 0),\n        var(--tw-exit-translate-y, 0),\n        0\n      )\n      scale3d(\n        var(--tw-exit-scale, 1),\n        var(--tw-exit-scale, 1),\n        var(--tw-exit-scale, 1)\n      )\n      rotate(var(--tw-exit-rotate, 0));\n  }\n}\n\n@utility animate-fadeIn {\n  animation: fadeIn 0.3s ease-out;\n}\n\n/* Scrollbar hiding utility */\n@utility scrollbar-none {\n  /* Hide scrollbar for Chrome, Safari and Opera */\n  .scrollbar-none::-webkit-scrollbar {\n    display: none;\n  }\n\n  /* Hide scrollbar for IE, Edge and Firefox */\n  .scrollbar-none {\n    -ms-overflow-style: none; /* IE and Edge */\n    scrollbar-width: none; /* Firefox */\n  }\n}\n\n@utility animate-slideIn {\n  animation: slideIn 0.3s ease-out;\n}\n\n@utility animate-in {\n  animation: in 150ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n@utility animate-out {\n  animation: out 150ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n@utility fade-in-0 {\n  --tw-enter-opacity: 0;\n}\n\n@utility fade-out-0 {\n  --tw-exit-opacity: 0;\n}\n\n@utility zoom-in-95 {\n  --tw-enter-scale: 0.95;\n}\n\n@utility zoom-out-95 {\n  --tw-exit-scale: 0.95;\n}\n\n@utility slide-in-from-top-2 {\n  --tw-enter-translate-y: -0.5rem;\n}\n\n@utility slide-in-from-bottom-2 {\n  --tw-enter-translate-y: 0.5rem;\n}\n\n@utility slide-in-from-left-2 {\n  --tw-enter-translate-x: -0.5rem;\n}\n\n@utility slide-in-from-right-2 {\n  --tw-enter-translate-x: 0.5rem;\n}\n\n@utility slide-out-to-top-2 {\n  --tw-exit-translate-y: -0.5rem;\n}\n\n@utility slide-out-to-bottom-2 {\n  --tw-exit-translate-y: 0.5rem;\n}\n\n@utility slide-out-to-left-2 {\n  --tw-exit-translate-x: -0.5rem;\n}\n\n@utility slide-out-to-right-2 {\n  --tw-exit-translate-x: 0.5rem;\n}\n\n@utility slide-in-from-top {\n  --tw-enter-translate-y: -100%;\n}\n\n@utility slide-in-from-bottom {\n  --tw-enter-translate-y: 100%;\n}\n\n@utility slide-in-from-left {\n  --tw-enter-translate-x: -100%;\n}\n\n@utility slide-in-from-right {\n  --tw-enter-translate-x: 100%;\n}\n\n@utility slide-out-to-top {\n  --tw-exit-translate-y: -100%;\n}\n\n@utility slide-out-to-bottom {\n  --tw-exit-translate-y: 100%;\n}\n\n@utility slide-out-to-left {\n  --tw-exit-translate-x: -100%;\n}\n\n@utility slide-out-to-right {\n  --tw-exit-translate-x: 100%;\n}\n\n@utility slide-in-from-left-half {\n  --tw-enter-translate-x: -50%;\n}\n\n@utility slide-in-from-top-48 {\n  --tw-enter-translate-y: -48%;\n}\n\n@utility slide-out-to-left-half {\n  --tw-exit-translate-x: -50%;\n}\n\n@utility slide-out-to-top-48 {\n  --tw-exit-translate-y: -48%;\n}\n\n/* Z-index utilities for portals */\n@utility z-50 {\n  z-index: 50;\n}\n\n/* Position utilities for dropdown positioning */\n@utility translate-y-1 {\n  transform: translateY(0.25rem);\n}\n\n@utility -translate-x-1 {\n  transform: translateX(-0.25rem);\n}\n\n@utility translate-x-1 {\n  transform: translateX(0.25rem);\n}\n\n@utility -translate-y-1 {\n  transform: translateY(-0.25rem);\n}\n\n@utility command-palette {\n  /* Command palette styles */\n  [cmdk-root] {\n    @apply bg-popover;\n  }\n\n  [cmdk-input] {\n    @apply bg-transparent;\n  }\n\n  [cmdk-item] {\n    @apply bg-transparent;\n  }\n\n  [cmdk-item][data-selected=\"true\"] {\n    @apply bg-accent text-accent-foreground;\n  }\n}\n\n@utility rule-builder {\n  /* Rule builder specific styles */\n  .rule-depth-indicator {\n    @apply absolute left-0 top-0 bottom-0 w-[3px] bg-gradient-to-b from-primary/80 to-primary/20;\n  }\n\n  .rule-path {\n    @apply font-mono text-xs text-muted-foreground;\n  }\n}\n\n@utility rule-indents {\n  /* Nested rule indentation */\n  .rule-indent-1 {\n    @apply pl-4;\n  }\n  .rule-indent-2 {\n    @apply pl-8;\n  }\n  .rule-indent-3 {\n    @apply pl-12;\n  }\n  .rule-indent-4 {\n    @apply pl-16;\n  }\n  .rule-indent-5 {\n    @apply pl-20;\n  }\n  .rule-indent-deep {\n    @apply pl-24 border-l-2 border-dashed border-border;\n  }\n}\n\n@utility calendar-styles {\n  /* React Day Picker styles */\n  .rdp {\n    @apply bg-popover text-popover-foreground;\n  }\n\n  .rdp-months {\n    @apply flex;\n  }\n\n  .rdp-month {\n    @apply space-y-4;\n  }\n\n  .rdp-caption {\n    @apply flex justify-center pt-1 relative items-center;\n  }\n\n  .rdp-caption_label {\n    @apply text-sm font-medium;\n  }\n\n  .rdp-nav {\n    @apply space-x-1 flex items-center;\n  }\n\n  .rdp-nav_button {\n    @apply h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 border border-input hover:bg-accent hover:text-accent-foreground;\n  }\n\n  .rdp-nav_button_previous {\n    @apply absolute left-1;\n  }\n\n  .rdp-nav_button_next {\n    @apply absolute right-1;\n  }\n\n  .rdp-table {\n    @apply w-full border-collapse space-y-1;\n  }\n\n  .rdp-head_row {\n    @apply flex;\n  }\n\n  .rdp-head_cell {\n    @apply text-muted-foreground rounded-md w-9 font-normal text-[0.8rem];\n  }\n\n  .rdp-row {\n    @apply flex w-full mt-2;\n  }\n\n  .rdp-cell {\n    @apply h-9 w-9 text-center text-sm p-0 relative focus-within:relative focus-within:z-20;\n  }\n\n  .rdp-day {\n    @apply h-9 w-9 p-0 font-normal inline-flex items-center justify-center rounded-md text-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground;\n  }\n\n  .rdp-day_selected {\n    @apply bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground;\n  }\n\n  .rdp-day_today {\n    @apply bg-accent text-accent-foreground;\n  }\n\n  .rdp-day_outside {\n    @apply text-muted-foreground opacity-50;\n  }\n\n  .rdp-day_disabled {\n    @apply text-muted-foreground opacity-50;\n  }\n\n  .rdp-day_range_middle {\n    @apply bg-accent/50;\n  }\n\n  .rdp-day_hidden {\n    @apply invisible;\n  }\n\n  .rdp-button:hover:not([disabled]) {\n    @apply bg-accent text-accent-foreground;\n  }\n\n  .rdp-button[disabled] {\n    @apply opacity-50 cursor-not-allowed;\n  }\n\n  /* Month switcher */\n  .rdp-month_grid {\n    @apply grid grid-cols-3 gap-4;\n  }\n\n  .rdp-focusable {\n    @apply cursor-pointer;\n  }\n\n  /* Additional calendar fixes */\n  [data-state=\"open\"] .rdp {\n    @apply animate-in fade-in-0 zoom-in-95;\n  }\n\n  [data-state=\"closed\"] .rdp {\n    @apply animate-out fade-out-0 zoom-out-95;\n  }\n}\n"
  },
  {
    "path": "packages/builder/src/test-demo.tsx",
    "content": "import { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { RuleBuilder } from \"./components/rule-builder\";\nimport { ecommerceFields } from \"./data/sample-data\";\nimport { operatorConfigs } from \"./utils/operators\";\nimport \"./styles/globals.css\";\n\nfunction TestDemo() {\n  return (\n    <div className=\"min-h-screen bg-gray-50 p-8\">\n      <div className=\"max-w-6xl mx-auto\">\n        <h1 className=\"text-3xl font-bold mb-8 text-gray-900\">\n          Rule Builder Test Demo\n        </h1>\n\n        <div className=\"bg-white p-6 rounded-lg shadow-lg\">\n          <RuleBuilder\n            fields={ecommerceFields}\n            operators={operatorConfigs}\n            onRuleChange={(rule: any) => {\n              console.log(\"Rule changed:\", JSON.stringify(rule, null, 2));\n            }}\n          />\n        </div>\n      </div>\n    </div>\n  );\n}\n\n// Only render if this is the main demo file being loaded\nif (typeof window !== \"undefined\" && document.getElementById(\"root\")) {\n  createRoot(document.getElementById(\"root\")!).render(\n    <StrictMode>\n      <TestDemo />\n    </StrictMode>,\n  );\n}\n\nexport default TestDemo;\n"
  },
  {
    "path": "packages/builder/src/test-store-debug.tsx",
    "content": "import { useUnifiedRuleStore } from \"./stores/unified-rule-store\";\nimport { ConditionTypes } from \"@usex/rule-engine\";\nimport { JsonViewer } from \"./components/JsonVisualizer\";\n\nfunction StoreDebugComponent() {\n  const store = useUnifiedRuleStore();\n\n  const testBasicFlow = () => {\n    console.log(\"=== Starting Basic Flow Test ===\");\n\n    // Step 1: Reset to clean state\n    store.resetRule();\n    console.log(\"After reset:\", JSON.stringify(store.rule, null, 2));\n\n    // Step 2: Add root AND condition (this is what the Add Condition Button does)\n    console.log(\"Calling addCondition('', ConditionTypes.AND)...\");\n    store.addCondition(\"\", ConditionTypes.AND);\n    console.log(\"After adding root AND:\", JSON.stringify(store.rule, null, 2));\n\n    // Check if hasConditions would be true now\n    const conditions = store.rule.conditions;\n    let hasConditions = false;\n    if (conditions) {\n      if (Array.isArray(conditions)) {\n        hasConditions = conditions.length > 0;\n      } else {\n        const condition = conditions as any;\n        hasConditions =\n          Object.keys(condition).length > 0 &&\n          (condition.and !== undefined ||\n            condition.or !== undefined ||\n            condition.none !== undefined);\n      }\n    }\n    console.log(\"hasConditions after adding root condition:\", hasConditions);\n\n    // Step 3: Add constraint to root AND\n    store.addConstraint(\"and\", {\n      field: \"user.age\",\n      operator: \"greater_than\" as any,\n      value: 18,\n    });\n    console.log(\n      \"After adding constraint:\",\n      JSON.stringify(store.rule, null, 2),\n    );\n\n    console.log(\"=== Basic Flow Test Complete ===\");\n  };\n\n  return (\n    <div className=\"max-w-6xl mx-auto p-6 space-y-6\">\n      <h2 className=\"text-xl font-bold text-gray-900 dark:text-white\">\n        Store Debug Test\n      </h2>\n\n      <button\n        type=\"button\"\n        onClick={testBasicFlow}\n        className=\"bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded transition-colors\"\n      >\n        Test Basic Flow\n      </button>\n\n      <div className=\"mt-8\">\n        <h3 className=\"font-bold text-gray-900 dark:text-white\">\n          Current Rule State:\n        </h3>\n        <div className=\"bg-gray-50 dark:bg-background p-4 mt-2 rounded-lg border border-gray-200 dark:border-gray-700\">\n          <JsonViewer\n            data={store.rule}\n            rootName=\"rule\"\n            defaultExpanded={true}\n            highlightLogicalOperators={true}\n            className=\"text-gray-900 dark:text-gray-100\"\n          />\n        </div>\n      </div>\n\n      <div className=\"mt-4\">\n        <h3 className=\"font-bold text-gray-900 dark:text-white\">\n          History Info:\n        </h3>\n        <p className=\"text-gray-700 dark:text-gray-300\">\n          Current: {store.getHistoryInfo().current}, Total:{\" \"}\n          {store.getHistoryInfo().total}\n        </p>\n      </div>\n    </div>\n  );\n}\n\nexport function StoreDebugTest() {\n  return <StoreDebugComponent />;\n}\n\nexport default StoreDebugTest;\n"
  },
  {
    "path": "packages/builder/src/types/index.ts",
    "content": "import type {\n  RuleType,\n  OperatorsType,\n  EngineResult,\n  Constraint,\n  ConditionType,\n  Condition,\n} from \"@usex/rule-engine\";\n\nexport interface RuleBuilderState {\n  rule: RuleType;\n  isDirty: boolean;\n  validationErrors: ValidationError[];\n}\n\nexport interface ValidationError {\n  path: string;\n  message: string;\n}\n\nexport interface RuleBuilderContextType {\n  state: RuleBuilderState;\n  updateRule: (rule: RuleType) => void;\n  updateConditions: (conditions: Condition | Condition[]) => void;\n  updateDefaultResult: (result: EngineResult | undefined) => void;\n  addCondition: (parentPath: string, conditionType: ConditionType) => void;\n  removeCondition: (path: string) => void;\n  updateCondition: (path: string, condition: Condition) => void;\n  addConstraint: (conditionPath: string, constraint: Constraint) => void;\n  updateConstraint: (path: string, constraint: Constraint) => void;\n  removeConstraint: (path: string) => void;\n  importRule: (rule: RuleType) => void;\n  exportRule: () => RuleType;\n  resetRule: () => void;\n  validate: () => boolean;\n}\n\nexport interface RuleBuilderProviderProps {\n  children: React.ReactNode;\n  initialRule?: RuleType;\n  onChange?: (rule: RuleType) => void;\n  onValidationError?: (errors: ValidationError[]) => void;\n}\n\nexport interface RuleBuilderProps {\n  className?: string;\n  showImportExport?: boolean;\n  showViewer?: boolean;\n  viewerPosition?: \"right\" | \"bottom\";\n  theme?: ThemeConfig;\n  fields?: FieldConfig[];\n  operators?: OperatorConfig[];\n  customValueInputs?: Record<string, React.ComponentType<ValueInputProps>>;\n  onRuleChange?: (rule: RuleType) => void;\n  readOnly?: boolean;\n}\n\nexport interface RuleEditorProps {\n  className?: string;\n  readOnly?: boolean;\n  fields?: FieldConfig[];\n  operators?: OperatorConfig[];\n}\n\nexport interface ConditionGroupProps {\n  condition: Condition;\n  path: string;\n  depth?: number;\n  readOnly?: boolean;\n  fields?: FieldConfig[];\n  operators?: OperatorConfig[];\n  onUpdate?: (condition: Condition) => void;\n  onRemove?: () => void;\n}\n\nexport interface ConstraintEditorProps {\n  constraint: Constraint;\n  path: string;\n  fields?: FieldConfig[];\n  operators?: OperatorConfig[];\n  readOnly?: boolean;\n  onUpdate?: (constraint: Constraint) => void;\n  onRemove?: () => void;\n}\n\nexport interface FieldSelectorProps {\n  value: string;\n  onChange: (value: string) => void;\n  fields?: FieldConfig[];\n  placeholder?: string;\n  disabled?: boolean;\n  className?: string;\n}\n\nexport interface OperatorSelectorProps {\n  value: OperatorsType;\n  onChange: (value: OperatorsType) => void;\n  operators?: OperatorConfig[];\n  field?: string;\n  disabled?: boolean;\n  className?: string;\n}\n\nexport interface ValueInputProps {\n  value: any;\n  onChange: (value: any) => void;\n  operator: OperatorsType;\n  field?: string;\n  disabled?: boolean;\n  className?: string;\n  placeholder?: string;\n}\n\nexport interface RuleViewerProps {\n  rule: RuleType;\n  className?: string;\n  syntaxHighlight?: boolean;\n  collapsible?: boolean;\n  defaultCollapsed?: boolean;\n}\n\nexport interface FieldConfig {\n  name: string;\n  label?: string;\n  type?: \"string\" | \"number\" | \"boolean\" | \"date\" | \"array\" | \"object\";\n  description?: string;\n  group?: string;\n  jsonPath?: boolean;\n  values?: Array<{ value: any; label: string }>;\n}\n\nexport interface OperatorConfig {\n  name: OperatorsType;\n  label?: string;\n  category?: string;\n  description?: string;\n  valueType?: \"none\" | \"single\" | \"multiple\" | \"range\";\n  applicableTypes?: Array<FieldConfig[\"type\"]>;\n}\n\nexport interface ThemeConfig {\n  colors?: {\n    primary?: string;\n    secondary?: string;\n    destructive?: string;\n    muted?: string;\n    accent?: string;\n    background?: string;\n    foreground?: string;\n    card?: string;\n    border?: string;\n  };\n  radius?: \"none\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\n  spacing?: \"compact\" | \"normal\" | \"comfortable\";\n  fontFamily?: string;\n}\n\nexport interface ImportExportProps {\n  onImport: (rule: RuleType) => void;\n  onExport: () => RuleType;\n  className?: string;\n}\n\nexport interface ResultEditorProps {\n  result?: EngineResult;\n  onChange: (result: EngineResult | undefined) => void;\n  label?: string;\n  placeholder?: string;\n  disabled?: boolean;\n  className?: string;\n}\n\nexport type ConditionPath = string;\nexport type ConstraintPath = string;\n"
  },
  {
    "path": "packages/builder/src/utils/json-path.ts",
    "content": "/**\n * Utilities for working with JSON Path expressions\n */\n\ninterface PathSegment {\n  type: \"property\" | \"index\" | \"wildcard\" | \"recursive\" | \"filter\";\n  value: string | number | null;\n  raw: string;\n}\n\n/**\n * Parse a JSON Path expression into segments\n */\nexport function parseJsonPath(path: string): PathSegment[] {\n  const segments: PathSegment[] = [];\n\n  if (!path.startsWith(\"$\")) {\n    throw new Error(\"JSON Path must start with $\");\n  }\n\n  // Remove the root $ and split by . Or [\n  const cleanPath = path.slice(1);\n  const parts = cleanPath.split(/(?=\\.)|(?=\\[)/);\n\n  for (const part of parts) {\n    if (!part) {\n      continue;\n    }\n\n    if (part.startsWith(\"..\")) {\n      // Recursive descent\n      segments.push({\n        type: \"recursive\",\n        value: part.slice(2),\n        raw: part,\n      });\n    } else if (part.startsWith(\".\")) {\n      // Property access\n      segments.push({\n        type: \"property\",\n        value: part.slice(1),\n        raw: part,\n      });\n    } else if (part.startsWith(\"[\")) {\n      const content = part.slice(1, -1);\n\n      if (content === \"*\") {\n        // Wildcard\n        segments.push({\n          type: \"wildcard\",\n          value: null,\n          raw: part,\n        });\n      } else if (content.startsWith(\"?\")) {\n        // Filter expression\n        segments.push({\n          type: \"filter\",\n          value: content,\n          raw: part,\n        });\n      } else {\n        // Array index\n        segments.push({\n          type: \"index\",\n          value: Number.parseInt(content, 10),\n          raw: part,\n        });\n      }\n    }\n  }\n\n  return segments;\n}\n\n/**\n * Build a JSON Path from segments\n */\nexport function buildJsonPath(segments: PathSegment[]): string {\n  let path = \"$\";\n\n  for (const segment of segments) {\n    switch (segment.type) {\n      case \"property\":\n        path += `.${segment.value}`;\n        break;\n      case \"index\":\n        path += `[${segment.value}]`;\n        break;\n      case \"wildcard\":\n        path += \"[*]\";\n        break;\n      case \"recursive\":\n        path += `..${segment.value}`;\n        break;\n      case \"filter\":\n        path += `[${segment.value}]`;\n        break;\n    }\n  }\n\n  return path;\n}\n\n/**\n * Get value from object using JSON Path\n */\nexport function getValueByPath(obj: any, path: string): any {\n  try {\n    const segments = parseJsonPath(path);\n    let current = obj;\n\n    for (const segment of segments) {\n      if (current === null || current === undefined) {\n        return undefined;\n      }\n\n      switch (segment.type) {\n        case \"property\":\n          current = current[segment.value as string];\n          break;\n\n        case \"index\":\n          if (Array.isArray(current)) {\n            current = current[segment.value as number];\n          } else {\n            return undefined;\n          }\n          break;\n\n        case \"wildcard\":\n          if (Array.isArray(current)) {\n            return current;\n          }\n          return undefined;\n\n        case \"recursive\": {\n          // Simple recursive search - returns first match\n          const searchKey = segment.value as string;\n          current = findRecursive(current, searchKey);\n          break;\n        }\n\n        case \"filter\":\n          // Basic filter support\n          if (Array.isArray(current)) {\n            // Very basic filter implementation\n            // In production, you'd want a proper filter expression parser\n            return current;\n          }\n          return undefined;\n      }\n    }\n\n    return current;\n  } catch {\n    return undefined;\n  }\n}\n\n/**\n * Recursively search for a key in an object\n */\nfunction findRecursive(obj: any, key: string): any {\n  if (obj === null || obj === undefined) {\n    return undefined;\n  }\n\n  if (typeof obj === \"object\") {\n    if (key in obj) {\n      return obj[key];\n    }\n\n    for (const k in obj) {\n      const result = findRecursive(obj[k], key);\n      if (result !== undefined) {\n        return result;\n      }\n    }\n  }\n\n  return undefined;\n}\n\n/**\n * Validate if a JSON Path is syntactically correct\n */\nexport function validateJsonPath(path: string): {\n  valid: boolean;\n  error?: string;\n} {\n  if (!path) {\n    return { valid: false, error: \"Path is required\" };\n  }\n\n  if (!path.startsWith(\"$\")) {\n    return { valid: false, error: \"Path must start with $\" };\n  }\n\n  try {\n    parseJsonPath(path);\n    return { valid: true };\n  } catch (error) {\n    return { valid: false, error: (error as Error).message };\n  }\n}\n\n/**\n * Get all possible paths from an object\n */\nexport function getAllPaths(obj: any, maxDepth: number = 10): string[] {\n  const paths: string[] = [];\n\n  function traverse(current: any, path: string, depth: number) {\n    if (depth > maxDepth) {\n      return;\n    }\n\n    if (current === null || current === undefined) {\n      return;\n    }\n\n    if (typeof current === \"object\") {\n      if (Array.isArray(current)) {\n        paths.push(`${path}[*]`);\n\n        // Sample first few items\n        current.slice(0, 3).forEach((item, index) => {\n          const itemPath = `${path}[${index}]`;\n          paths.push(itemPath);\n          traverse(item, itemPath, depth + 1);\n        });\n      } else {\n        for (const key in current) {\n          const newPath = `${path}.${key}`;\n          paths.push(newPath);\n          traverse(current[key], newPath, depth + 1);\n        }\n      }\n    }\n  }\n\n  traverse(obj, \"$\", 0);\n  return paths;\n}\n\n/**\n * Convert simple field name to JSON Path\n */\nexport function fieldToJsonPath(field: string): string {\n  if (field.startsWith(\"$\")) {\n    return field;\n  }\n\n  return `$.${field}`;\n}\n\n/**\n * Extract field name from JSON Path\n */\nexport function jsonPathToField(path: string): string {\n  if (!path.startsWith(\"$\")) {\n    return path;\n  }\n\n  // Simple paths like $.field\n  if (path.match(/^\\$\\.\\w+$/)) {\n    return path.slice(2);\n  }\n\n  // Return full path for complex expressions\n  return path;\n}\n\n/**\n * Build a JSON Path from parts\n */\nexport function buildPath(...parts: (string | number)[]): string {\n  let path = \"$\";\n\n  for (const part of parts) {\n    if (typeof part === \"number\") {\n      path += `[${part}]`;\n    } else if (part === \"*\") {\n      path += \"[*]\";\n    } else if (part.startsWith(\"[\") && part.endsWith(\"]\")) {\n      path += part;\n    } else {\n      path += `.${part}`;\n    }\n  }\n\n  return path;\n}\n"
  },
  {
    "path": "packages/builder/src/utils/operators.ts",
    "content": "import { Operators } from \"@usex/rule-engine\";\nimport type { OperatorsType } from \"@usex/rule-engine\";\nimport type { OperatorConfig } from \"../types\";\n\nexport const operatorCategories = {\n  comparison: \"Comparison\",\n  array: \"Array/Collection\",\n  existence: \"Existence\",\n  date: \"Date/Time\",\n  type: \"Type Validation\",\n  string: \"String Validation\",\n  number: \"Number Validation\",\n  length: \"Length Validation\",\n  boolean: \"Boolean Validation\",\n} as const;\n\nexport const operatorConfigs: OperatorConfig[] = [\n  // Comparison Operators\n  {\n    name: Operators.Equals,\n    label: \"Equals\",\n    category: operatorCategories.comparison,\n    valueType: \"single\",\n  },\n  {\n    name: Operators.NotEquals,\n    label: \"Not Equals\",\n    category: operatorCategories.comparison,\n    valueType: \"single\",\n  },\n  {\n    name: Operators.Like,\n    label: \"Like\",\n    category: operatorCategories.comparison,\n    valueType: \"single\",\n    applicableTypes: [\"string\"],\n  },\n  {\n    name: Operators.NotLike,\n    label: \"Not Like\",\n    category: operatorCategories.comparison,\n    valueType: \"single\",\n    applicableTypes: [\"string\"],\n  },\n  {\n    name: Operators.GreaterThan,\n    label: \"Greater Than\",\n    category: operatorCategories.comparison,\n    valueType: \"single\",\n    applicableTypes: [\"number\", \"date\"],\n  },\n  {\n    name: Operators.LessThan,\n    label: \"Less Than\",\n    category: operatorCategories.comparison,\n    valueType: \"single\",\n    applicableTypes: [\"number\", \"date\"],\n  },\n  {\n    name: Operators.GreaterThanOrEquals,\n    label: \"Greater Than or Equals\",\n    category: operatorCategories.comparison,\n    valueType: \"single\",\n    applicableTypes: [\"number\", \"date\"],\n  },\n  {\n    name: Operators.LessThanOrEquals,\n    label: \"Less Than or Equals\",\n    category: operatorCategories.comparison,\n    valueType: \"single\",\n    applicableTypes: [\"number\", \"date\"],\n  },\n\n  // Array/Collection Operators\n  {\n    name: Operators.In,\n    label: \"In\",\n    category: operatorCategories.array,\n    valueType: \"multiple\",\n  },\n  {\n    name: Operators.NotIn,\n    label: \"Not In\",\n    category: operatorCategories.array,\n    valueType: \"multiple\",\n  },\n  {\n    name: Operators.Contains,\n    label: \"Contains\",\n    category: operatorCategories.array,\n    valueType: \"single\",\n  },\n  {\n    name: Operators.NotContains,\n    label: \"Not Contains\",\n    category: operatorCategories.array,\n    valueType: \"single\",\n  },\n  {\n    name: Operators.ContainsAny,\n    label: \"Contains Any\",\n    category: operatorCategories.array,\n    valueType: \"multiple\",\n  },\n  {\n    name: Operators.ContainsAll,\n    label: \"Contains All\",\n    category: operatorCategories.array,\n    valueType: \"multiple\",\n  },\n\n  // Existence/Nullability\n  {\n    name: Operators.Exists,\n    label: \"Exists\",\n    category: operatorCategories.existence,\n    valueType: \"none\",\n  },\n  {\n    name: Operators.NotExists,\n    label: \"Not Exists\",\n    category: operatorCategories.existence,\n    valueType: \"none\",\n  },\n  {\n    name: Operators.NullOrUndefined,\n    label: \"Null or Undefined\",\n    category: operatorCategories.existence,\n    valueType: \"none\",\n  },\n  {\n    name: Operators.NotNullOrUndefined,\n    label: \"Not Null or Undefined\",\n    category: operatorCategories.existence,\n    valueType: \"none\",\n  },\n  {\n    name: Operators.Empty,\n    label: \"Empty\",\n    category: operatorCategories.existence,\n    valueType: \"none\",\n  },\n  {\n    name: Operators.NotEmpty,\n    label: \"Not Empty\",\n    category: operatorCategories.existence,\n    valueType: \"none\",\n  },\n\n  // Date/Time Operators\n  {\n    name: Operators.DateAfter,\n    label: \"Date After\",\n    category: operatorCategories.date,\n    valueType: \"single\",\n    applicableTypes: [\"date\"],\n  },\n  {\n    name: Operators.DateBefore,\n    label: \"Date Before\",\n    category: operatorCategories.date,\n    valueType: \"single\",\n    applicableTypes: [\"date\"],\n  },\n  {\n    name: Operators.DateEquals,\n    label: \"Date Equals\",\n    category: operatorCategories.date,\n    valueType: \"single\",\n    applicableTypes: [\"date\"],\n  },\n  {\n    name: Operators.DateBetween,\n    label: \"Date Between\",\n    category: operatorCategories.date,\n    valueType: \"range\",\n    applicableTypes: [\"date\"],\n  },\n  {\n    name: Operators.DateAfterNow,\n    label: \"Date After Now\",\n    category: operatorCategories.date,\n    valueType: \"none\",\n    applicableTypes: [\"date\"],\n  },\n  {\n    name: Operators.DateBeforeNow,\n    label: \"Date Before Now\",\n    category: operatorCategories.date,\n    valueType: \"none\",\n    applicableTypes: [\"date\"],\n  },\n\n  // Type Validation\n  {\n    name: Operators.String,\n    label: \"Is String\",\n    category: operatorCategories.type,\n    valueType: \"none\",\n  },\n  {\n    name: Operators.Number,\n    label: \"Is Number\",\n    category: operatorCategories.type,\n    valueType: \"none\",\n  },\n  {\n    name: Operators.Boolean,\n    label: \"Is Boolean\",\n    category: operatorCategories.type,\n    valueType: \"none\",\n  },\n  {\n    name: Operators.Array,\n    label: \"Is Array\",\n    category: operatorCategories.type,\n    valueType: \"none\",\n  },\n  {\n    name: Operators.Object,\n    label: \"Is Object\",\n    category: operatorCategories.type,\n    valueType: \"none\",\n  },\n  {\n    name: Operators.Email,\n    label: \"Is Email\",\n    category: operatorCategories.type,\n    valueType: \"none\",\n    applicableTypes: [\"string\"],\n  },\n  {\n    name: Operators.Url,\n    label: \"Is URL\",\n    category: operatorCategories.type,\n    valueType: \"none\",\n    applicableTypes: [\"string\"],\n  },\n  {\n    name: Operators.UUID,\n    label: \"Is UUID\",\n    category: operatorCategories.type,\n    valueType: \"none\",\n    applicableTypes: [\"string\"],\n  },\n\n  // String Validation\n  {\n    name: Operators.Alpha,\n    label: \"Alpha\",\n    category: operatorCategories.string,\n    valueType: \"none\",\n    applicableTypes: [\"string\"],\n  },\n  {\n    name: Operators.AlphaNumeric,\n    label: \"Alpha Numeric\",\n    category: operatorCategories.string,\n    valueType: \"none\",\n    applicableTypes: [\"string\"],\n  },\n  {\n    name: Operators.LowerCase,\n    label: \"Lower Case\",\n    category: operatorCategories.string,\n    valueType: \"none\",\n    applicableTypes: [\"string\"],\n  },\n  {\n    name: Operators.UpperCase,\n    label: \"Upper Case\",\n    category: operatorCategories.string,\n    valueType: \"none\",\n    applicableTypes: [\"string\"],\n  },\n  {\n    name: Operators.Matches,\n    label: \"Matches (Regex)\",\n    category: operatorCategories.string,\n    valueType: \"single\",\n    applicableTypes: [\"string\"],\n  },\n  {\n    name: Operators.NotMatches,\n    label: \"Not Matches (Regex)\",\n    category: operatorCategories.string,\n    valueType: \"single\",\n    applicableTypes: [\"string\"],\n  },\n\n  // Number Validation\n  {\n    name: Operators.Positive,\n    label: \"Positive\",\n    category: operatorCategories.number,\n    valueType: \"none\",\n    applicableTypes: [\"number\"],\n  },\n  {\n    name: Operators.Negative,\n    label: \"Negative\",\n    category: operatorCategories.number,\n    valueType: \"none\",\n    applicableTypes: [\"number\"],\n  },\n  {\n    name: Operators.Zero,\n    label: \"Zero\",\n    category: operatorCategories.number,\n    valueType: \"none\",\n    applicableTypes: [\"number\"],\n  },\n  {\n    name: Operators.Min,\n    label: \"Minimum\",\n    category: operatorCategories.number,\n    valueType: \"single\",\n    applicableTypes: [\"number\"],\n  },\n  {\n    name: Operators.Max,\n    label: \"Maximum\",\n    category: operatorCategories.number,\n    valueType: \"single\",\n    applicableTypes: [\"number\"],\n  },\n  {\n    name: Operators.Between,\n    label: \"Between\",\n    category: operatorCategories.number,\n    valueType: \"range\",\n    applicableTypes: [\"number\"],\n  },\n\n  // Length Validation\n  {\n    name: Operators.StringLength,\n    label: \"String Length\",\n    category: operatorCategories.length,\n    valueType: \"single\",\n    applicableTypes: [\"string\"],\n  },\n  {\n    name: Operators.MinLength,\n    label: \"Min Length\",\n    category: operatorCategories.length,\n    valueType: \"single\",\n    applicableTypes: [\"string\", \"array\"],\n  },\n  {\n    name: Operators.MaxLength,\n    label: \"Max Length\",\n    category: operatorCategories.length,\n    valueType: \"single\",\n    applicableTypes: [\"string\", \"array\"],\n  },\n  {\n    name: Operators.LengthBetween,\n    label: \"Length Between\",\n    category: operatorCategories.length,\n    valueType: \"range\",\n    applicableTypes: [\"string\", \"array\"],\n  },\n\n  // Boolean Validation\n  {\n    name: Operators.Truthy,\n    label: \"Truthy\",\n    category: operatorCategories.boolean,\n    valueType: \"none\",\n  },\n  {\n    name: Operators.Falsy,\n    label: \"Falsy\",\n    category: operatorCategories.boolean,\n    valueType: \"none\",\n  },\n];\n\nexport const getOperatorConfig = (\n  operator: OperatorsType,\n): OperatorConfig | undefined => {\n  return operatorConfigs.find((config) => config.name === operator);\n};\n\nexport const getOperatorsByCategory = (category: string): OperatorConfig[] => {\n  return operatorConfigs.filter((config) => config.category === category);\n};\n\nexport const getOperatorsForFieldType = (\n  fieldType?: string,\n): OperatorConfig[] => {\n  if (!fieldType) return operatorConfigs;\n\n  return operatorConfigs.filter((config) => {\n    if (!config.applicableTypes || config.applicableTypes.length === 0) {\n      return true;\n    }\n    return config.applicableTypes.includes(fieldType as any);\n  });\n};\n"
  },
  {
    "path": "packages/builder/src/vite-env.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "packages/builder/tsconfig.app.json",
    "content": "{\n  \"compilerOptions\": {\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.app.tsbuildinfo\",\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"skipLibCheck\": true,\n\n    /* Bundler mode */\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"verbatimModuleSyntax\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n\n    /* Linting */\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"erasableSyntaxOnly\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"noUncheckedSideEffectImports\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/builder/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"references\": [\n    { \"path\": \"./tsconfig.app.json\" },\n    { \"path\": \"./tsconfig.node.json\" }\n  ],\n  \"files\": []\n}\n"
  },
  {
    "path": "packages/builder/tsconfig.node.json",
    "content": "{\n  \"compilerOptions\": {\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n    \"target\": \"ES2022\",\n    \"lib\": [\"ES2023\"],\n    \"module\": \"ESNext\",\n    \"skipLibCheck\": true,\n\n    /* Bundler mode */\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"verbatimModuleSyntax\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n\n    /* Linting */\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"erasableSyntaxOnly\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"noUncheckedSideEffectImports\": true\n  },\n  \"include\": [\"vite.config.ts\"]\n}\n"
  },
  {
    "path": "packages/builder/vercel.json",
    "content": "{\n  \"installCommand\": \"pnpm install --frozen-lockfile\",\n  \"buildCommand\": \"pnpm run build:demo\",\n  \"outputDirectory\": \"dist-demo\"\n}"
  },
  {
    "path": "packages/builder/vite.config.ts",
    "content": "import { defineConfig } from \"vite\";\nimport tailwindcss from \"@tailwindcss/vite\";\nimport react from \"@vitejs/plugin-react-swc\";\nimport dts from \"vite-plugin-dts\";\nimport path from \"node:path\";\nimport { nodePolyfills } from \"vite-plugin-node-polyfills\";\n\nconst isDemoMode = process.env.BUILD_MODE === \"demo\";\n\n// https://vite.dev/config/\nexport default defineConfig({\n  plugins: [\n    react(),\n    tailwindcss(),\n    !isDemoMode &&\n      dts({\n        include: [\"src/**/*.ts\", \"src/**/*.tsx\"],\n        exclude: [\"src/demo.tsx\", \"src/main.tsx\", \"src/vite-env.d.ts\"],\n        entryRoot: \"src\",\n        outDir: \"dist\",\n        insertTypesEntry: true,\n      }),\n    nodePolyfills({\n      include: [\"crypto\", \"stream\", \"vm\", \"buffer\", \"path\", \"url\"],\n    }),\n  ].filter(Boolean),\n  build: isDemoMode\n    ? {\n        // Demo build configuration\n        outDir: \"dist-demo\",\n        rollupOptions: {\n          input: {\n            main: path.resolve(__dirname, \"index.html\"),\n          },\n        },\n      }\n    : {\n        // Library build configuration\n        outDir: \"dist\",\n        lib: {\n          entry: path.resolve(__dirname, \"src/index.ts\"),\n          name: \"RuleEngineBuilder\",\n          formats: [\"es\", \"cjs\"],\n          fileName: \"index\",\n        },\n        rollupOptions: {\n          external: [\n            \"react\",\n            \"react-dom\",\n            \"react/jsx-runtime\",\n            \"vite-plugin-node-polyfills/shims/process\",\n          ],\n          output: {\n            globals: {\n              react: \"React\",\n              \"react-dom\": \"ReactDOM\",\n              \"react/jsx-runtime\": \"react/jsx-runtime\",\n            },\n          },\n        },\n      },\n});\n"
  },
  {
    "path": "packages/core/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n\n### [0.0.2](https://github.com/ali-master/rule-engine/compare/v0.0.1...v0.0.2) (2025-06-10)\n\n### 0.0.1 (2025-06-10)\n\n\n### Features\n\n* **AdvancedFieldInput:** refactor code for improved readability and maintainability ([8e3e1ff](https://github.com/ali-master/rule-engine/commit/8e3e1ff74c3c1dc60128850eb87b57c1cb2ade23))\n* **App, TreeRuleBuilder, UndoRedoInfo:** integrate enhanced rule store with undo/redo functionality and keyboard shortcuts ([e85e89b](https://github.com/ali-master/rule-engine/commit/e85e89bebe0fec64d04f370dcf6342aadcd74067))\n* **App:** implement rule evaluation feature with UI enhancements ([be42689](https://github.com/ali-master/rule-engine/commit/be42689773b385ac4bb8504920e53483e9977766))\n* **builder:** add shadcn ([216c8a7](https://github.com/ali-master/rule-engine/commit/216c8a7ac425e64e3344b9aa441f35bfd64df6d2))\n* **Builder:** added the smart builder ui ([eeb9468](https://github.com/ali-master/rule-engine/commit/eeb94685a16863288d6f51d4b4a136e03a41790e))\n* **Calendar, DateInput, TreeConstraintEditor:** enhance calendar functionality and add animations ([94404e4](https://github.com/ali-master/rule-engine/commit/94404e49bd607e791721dcc6ba30d7a85d849efb))\n* **DateInput, TreeConstraintEditor:** enhance date parsing and add visual field selector ([b9dd735](https://github.com/ali-master/rule-engine/commit/b9dd735a038703c559a9d1f32ba7f0ddbf71a522))\n* **Dialog:** refactor dialog components for improved readability and structure ([c530113](https://github.com/ali-master/rule-engine/commit/c530113d58b01f9f3c1ebf916652dff10580d70f))\n* **DiffViewer:** add DiffStats component for enhanced property change visualization ([f8f74c5](https://github.com/ali-master/rule-engine/commit/f8f74c57f486c6b426dceae17cbeb059991b9594))\n* **EditableJsonViewer:** add keyboard shortcuts for live evaluation and enhance tooltip information ([6cfb41f](https://github.com/ali-master/rule-engine/commit/6cfb41f268b751e50c998ae47741d12585f11d40))\n* **EditableJsonViewer:** add live evaluation feature and improve diff visualization ([fc4caee](https://github.com/ali-master/rule-engine/commit/fc4caeeba4d8d63657bf637d5bac1828670e8042))\n* **HistoryViewer:** implement history viewer with search, filter, and version comparison features ([77c52c0](https://github.com/ali-master/rule-engine/commit/77c52c0d51aa7628a4e1180f19125c87dbe47e8a))\n* **HistoryViewer:** integrate ResizablePanel for improved layout flexibility ([bc7b918](https://github.com/ali-master/rule-engine/commit/bc7b9185f9c3db1a4a91a16201a634b37f3d0de0))\n* **HistoryViewer:** replace select element with custom Select component for action filtering ([ffc7b07](https://github.com/ali-master/rule-engine/commit/ffc7b0799e72816e5da692d47e8393cd668075c6))\n* **JsonViewer:** add highlight for logical operators and improve scrollbar handling ([9f159bc](https://github.com/ali-master/rule-engine/commit/9f159bc9f6a33d2f479e27be225c48961074d826))\n* **JsonViewer:** integrate JsonViewer component for improved JSON display and editing experience ([8ead760](https://github.com/ali-master/rule-engine/commit/8ead7605c7257c1a493d6273af682dc632041e8c))\n* **OperatorSelector:** add search functionality and improve operator grouping ([10dd6c4](https://github.com/ali-master/rule-engine/commit/10dd6c484d176c0ed49ac0d7c69b36d8ce82e05f))\n* **TreeConditionGroup:** enhance condition type styling with improved colors and animations ([aa5bb4a](https://github.com/ali-master/rule-engine/commit/aa5bb4ae10afcb9e78f006f5cd974d5858fc8d57))\n* **TreeConstraintEditor:** add advanced field selector mode and integrate SmartOperatorSelector ([03d40ec](https://github.com/ali-master/rule-engine/commit/03d40ec93341580f3e375c0f4450c39cdc75c5a4))\n* **TreeConstraintEditor:** enhance operator selection with tooltips and improved layout ([cd7a728](https://github.com/ali-master/rule-engine/commit/cd7a728326da6f26077146f3ce1df2cbbb178f4a))\n* **TreeRuleBuilder, VisualFieldSelector:** enhance UI with regex helper and improved tab functionality ([cacef1a](https://github.com/ali-master/rule-engine/commit/cacef1a27bf932753df20319cd43b7a4f1da19b4))\n* **VisualFieldSelector:** enhance value preview layout and improve JsonViewer integration ([59d962a](https://github.com/ali-master/rule-engine/commit/59d962ae12b3127a666eab8b105feadc45cfa77c))\n* **VisualFieldSelector:** integrate JsonViewer for enhanced JSON value preview ([52bb37c](https://github.com/ali-master/rule-engine/commit/52bb37c1112e6d857d28cb430c58692c6c579d3a))\n\n\n### Bug Fixes\n\n* **HistoryViewer:** layout and overflow ([7f357a4](https://github.com/ali-master/rule-engine/commit/7f357a49bf7b9904e6bc964ff40ed85779d52eec))\n"
  },
  {
    "path": "packages/core/README.md",
    "content": "<div align=\"center\">\n  <img src=\"../../assets/core-logo.svg\" alt=\"Rule Engine Core Logo\" width=\"120\" />\n\n  <h1>@usex/rule-engine</h1>\n  <p><strong>🎯 The Developer's Decision Engine</strong></p>\n\n  <p>\n    <a href=\"https://www.npmjs.com/package/@usex/rule-engine\"><img src=\"https://img.shields.io/npm/v/@usex/rule-engine?style=flat-square\" alt=\"npm version\" /></a>\n    <a href=\"https://github.com/ali-master/rule-engine/blob/master/LICENSE\"><img src=\"https://img.shields.io/npm/l/@usex/rule-engine?style=flat-square\" alt=\"license\" /></a>\n    <a href=\"https://codecov.io/gh/ali-master/rule-engine\"><img src=\"https://codecov.io/gh/ali-master/rule-engine/graph/badge.svg?token=UN5opqxNsi\" alt=\"codecov\" /></a>\n    <a href=\"https://www.npmjs.com/package/@usex/rule-engine\"><img src=\"https://img.shields.io/npm/dm/@usex/rule-engine?style=flat-square\" alt=\"downloads\" /></a>\n    <a href=\"https://github.com/ali-master/rule-engine\"><img src=\"https://img.shields.io/github/stars/ali-master/rule-engine?style=flat-square\" alt=\"stars\" /></a>\n  </p>\n\n  <p>\n    <a href=\"#-quick-start\">Quick Start</a> •\n    <a href=\"./docs/api-reference-v2.md\">API Reference</a> •\n    <a href=\"./docs/typescript-guide.md\">TypeScript Guide</a> •\n    <a href=\"#-why-rule-engine\">Why Rule Engine?</a>\n  </p>\n</div>\n\n---\n\nTransform complex business logic into elegant, maintainable JSON rules. Stop hardcoding decisions, start building intelligent systems.\n\n```typescript\n// From this mess...\nif (user.tier === 'vip' && order.total > 100 && user.country === 'US') {\n  return { discount: 0.20, shipping: 'free' };\n} else if (user.isNew && order.total > 50) {\n  return { discount: 0.10, shipping: 'standard' };\n} // ... 50 more lines\n\n// To this elegance...\nconst result = await RuleEngine.evaluate(discountRules, { user, order });\n```\n\n## 🚀 Why Rule Engine?\n\n**Built for Modern Developers**\n- 🎯 **Zero Dependencies** - No supply chain bloat, just pure JavaScript excellence\n- 🏎️ **Lightning Fast** - 17,000+ rule evaluations per second with complex JSONPath support at 55,000+ ops/sec\n- 🛡️ **TypeScript Native** - Built-in generics for bulletproof type safety\n- 🌐 **Universal** - Node.js, browsers, edge functions, Deno, Bun - everywhere JavaScript runs\n\n**Powerful Yet Intuitive**\n- 🔍 **JSONPath Support** - Navigate complex objects: `$.user.profile.settings.theme`\n- 🔗 **Self-Referencing** - Dynamic field references: `\"value\": \"$.maxPrice\"`\n- 🧩 **121+ Operators** - From basic comparisons to advanced pattern matching\n- 🏗️ **Fluent Builder** - Construct rules programmatically with intuitive chains\n\n**Enterprise Ready**\n- 🔧 **Extensible Core** - Plugin custom operators without touching internals\n- 📊 **Rule Introspection** - Reverse-engineer possible inputs from rule definitions\n- ⚡ **Performance Optimized** - Optional validation bypass for trusted rules\n- 🎭 **Data Mutations** - Preprocess data before evaluation\n\n## 🎬 Quick Start\n\n```bash\nnpm install @usex/rule-engine\n```\n\n### Your First Rule in 30 Seconds\n\n```typescript\nimport { RuleEngine } from '@usex/rule-engine';\n\n// Define a discount rule\nconst discountRule = {\n  conditions: [\n    {\n      // VIP customers get 20% off orders over $100\n      and: [\n        { field: \"$.customer.tier\", operator: \"equals\", value: \"vip\" },\n        { field: \"$.order.total\", operator: \"greater-than\", value: 100 }\n      ],\n      result: { discount: 0.20, message: \"VIP discount applied! 🎉\" }\n    },\n    {\n      // First-time buyers get 10% off orders over $50\n      and: [\n        { field: \"$.customer.orderCount\", operator: \"equals\", value: 0 },\n        { field: \"$.order.total\", operator: \"greater-than\", value: 50 }\n      ],\n      result: { discount: 0.10, message: \"Welcome! First order discount 🎁\" }\n    }\n  ],\n  default: { discount: 0, message: \"No discount available\" }\n};\n\n// Apply the rule\nconst orderData = {\n  customer: { tier: \"vip\", orderCount: 5 },\n  order: { total: 150, items: [\"laptop\", \"mouse\"] }\n};\n\nconst result = await RuleEngine.evaluate(discountRule, orderData);\nconsole.log(result);\n// { value: { discount: 0.20, message: \"VIP discount applied! 🎉\" }, isPassed: true }\n```\n\n## 🏗️ Core Concepts\n\n### Rules Structure\nEvery rule follows this pattern:\n```typescript\ninterface Rule<T = any> {\n  conditions: Condition<T> | Condition<T>[];  // What to check\n  default?: T;                                // Fallback result\n}\n```\n\n### Conditions: Your Logic Building Blocks\n```typescript\ninterface Condition<T = any> {\n  and?: Array<Constraint | Condition<T>>;   // ALL must match\n  or?: Array<Constraint | Condition<T>>;    // ANY must match\n  none?: Array<Constraint | Condition<T>>;  // NONE must match\n  result?: T;                               // What to return when matched\n}\n```\n\n### Constraints: The Evaluation Units\n```typescript\ninterface Constraint {\n  field: string;      // Path to the data (supports JSONPath)\n  operator: string;   // How to compare\n  value: any;         // What to compare against\n  message?: string;   // Optional validation message\n}\n```\n\n## 🛠️ API Reference\n\n### Static Methods (Recommended)\n\n| Method | Description | Returns |\n|--------|-------------|---------|\n| `RuleEngine.evaluate(rule, data, trustRule?)` | Full evaluation with metadata | `Promise<EvaluationResult<T>>` |\n| `RuleEngine.checkIsPassed(rule, data, trustRule?)` | Quick boolean check | `Promise<boolean>` |\n| `RuleEngine.getEvaluateResult(rule, data, trustRule?)` | Just the result value | `Promise<T>` |\n| `RuleEngine.evaluateMany(rules, data, trustRule?)` | Batch evaluation | `Promise<EvaluationResult<T>[]>` |\n| `RuleEngine.validate(rule)` | Validate rule structure | `ValidationResult` |\n| `RuleEngine.introspect(rule)` | Analyze rule requirements | `IntrospectionResult` |\n| `RuleEngine.builder()` | Get fluent builder | `RuleBuilder` |\n\n### Instance Methods\n```typescript\nconst engine = new RuleEngine();\n// All static methods available as instance methods\nawait engine.evaluate(rule, data);\n```\n\n## 🔧 Operators Showcase\n\n### String & Text\n```typescript\n// Basic string operations\n{ field: \"name\", operator: \"equals\", value: \"John\" }\n{ field: \"email\", operator: \"like\", value: \"*@gmail.com\" }\n{ field: \"description\", operator: \"matches\", value: \"^Product.*\" }\n\n// Validation\n{ field: \"email\", operator: \"email\", value: true }\n{ field: \"url\", operator: \"url\", value: true }\n{ field: \"uuid\", operator: \"uuid\", value: true }\n```\n\n### Numbers & Ranges\n```typescript\n// Comparisons\n{ field: \"age\", operator: \"greater-than\", value: 18 }\n{ field: \"price\", operator: \"between\", value: [10, 100] }\n\n// Types\n{ field: \"score\", operator: \"integer\", value: true }\n{ field: \"rating\", operator: \"positive\", value: true }\n```\n\n### Arrays & Collections\n```typescript\n// Membership\n{ field: \"roles\", operator: \"contains\", value: \"admin\" }\n{ field: \"status\", operator: \"in\", value: [\"active\", \"pending\"] }\n{ field: \"tags\", operator: \"contains-all\", value: [\"urgent\", \"review\"] }\n{ field: \"features\", operator: \"contains-any\", value: [\"premium\", \"beta\"] }\n```\n\n### Date & Time\n```typescript\n// Date comparisons\n{ field: \"birthDate\", operator: \"date-after\", value: \"1990-01-01\" }\n{ field: \"expiryDate\", operator: \"date-before-now\", value: true }\n{ field: \"createdAt\", operator: \"date-between\", value: [\"2023-01-01\", \"2023-12-31\"] }\n\n// Time comparisons\n{ field: \"openTime\", operator: \"time-after\", value: \"09:00\" }\n{ field: \"closeTime\", operator: \"time-before\", value: \"17:30\" }\n```\n\n### Existence & Nullability\n```typescript\n// Existence checks\n{ field: \"optional\", operator: \"exists\", value: true }\n{ field: \"deprecated\", operator: \"not-exists\", value: true }\n\n// Null checks\n{ field: \"data\", operator: \"null-or-undefined\", value: false }\n{ field: \"config\", operator: \"not-empty\", value: true }\n```\n\n### Length & Size\n```typescript\n// String length\n{ field: \"password\", operator: \"min-length\", value: 8 }\n{ field: \"username\", operator: \"max-length\", value: 20 }\n{ field: \"code\", operator: \"string-length\", value: 6 }\n{ field: \"description\", operator: \"length-between\", value: [10, 500] }\n```\n\n## 🎯 Real-World Examples\n\n### 🛒 E-commerce Pricing Engine\n```typescript\nconst pricingRules = {\n  conditions: [\n    {\n      // Black Friday: 50% off everything\n      and: [\n        { field: \"$.event.name\", operator: \"equals\", value: \"black-friday\" },\n        { field: \"$.event.active\", operator: \"equals\", value: true }\n      ],\n      result: {\n        discount: 0.50,\n        code: \"BLACKFRIDAY50\",\n        expires: \"2025-11-30T23:59:59Z\"\n      }\n    },\n    {\n      // Bulk orders: tiered discounts\n      or: [\n        { field: \"$.cart.quantity\", operator: \"greater-than\", value: 50 },\n        { field: \"$.cart.value\", operator: \"greater-than\", value: 1000 }\n      ],\n      result: {\n        discount: 0.15,\n        code: \"BULK15\",\n        shipping: \"free\"\n      }\n    },\n    {\n      // New customer welcome\n      and: [\n        { field: \"$.customer.orderHistory.length\", operator: \"equals\", value: 0 },\n        { field: \"$.cart.value\", operator: \"greater-than\", value: 50 }\n      ],\n      result: {\n        discount: 0.10,\n        code: \"WELCOME10\",\n        message: \"Welcome! Enjoy 10% off your first order 🎉\"\n      }\n    }\n  ],\n  default: { discount: 0, message: \"Regular pricing applies\" }\n};\n```\n\n### 🔐 Dynamic Access Control\n```typescript\nconst accessControlRules = {\n  conditions: [\n    {\n      // Super admin: full access\n      and: [\n        { field: \"role\", operator: \"equals\", value: \"super-admin\" },\n        { field: \"status\", operator: \"equals\", value: \"active\" }\n      ],\n      result: {\n        permissions: [\"read\", \"write\", \"delete\", \"admin\"],\n        level: \"unlimited\",\n        expires: null\n      }\n    },\n    {\n      // Department manager: departmental access\n      and: [\n        { field: \"role\", operator: \"equals\", value: \"manager\" },\n        { field: \"department\", operator: \"exists\", value: true },\n        { field: \"$.session.loginTime\", operator: \"date-after-now\", value: \"-8h\" }\n      ],\n      result: {\n        permissions: [\"read\", \"write\"],\n        level: \"department\",\n        scope: \"$.department\",\n        expires: \"$.session.loginTime + 8h\"\n      }\n    },\n    {\n      // Regular user: read-only during business hours\n      and: [\n        { field: \"role\", operator: \"equals\", value: \"user\" },\n        { field: \"$.currentTime\", operator: \"time-between\", value: [\"09:00\", \"17:00\"] },\n        { field: \"$.currentTime\", operator: \"date-between\", value: [\"monday\", \"friday\"] }\n      ],\n      result: {\n        permissions: [\"read\"],\n        level: \"limited\",\n        expires: \"17:00\"\n      }\n    }\n  ],\n  default: {\n    permissions: [],\n    level: \"none\",\n    message: \"Access denied\"\n  }\n};\n```\n\n### ✅ Smart Form Validation\n```typescript\nconst registrationValidation = {\n  conditions: {\n    and: [\n      // Email validation with custom message\n      {\n        field: \"email\",\n        operator: \"email\",\n        value: true,\n        message: \"Please enter a valid email address\"\n      },\n\n      // Strong password requirements\n      {\n        and: [\n          {\n            field: \"password\",\n            operator: \"min-length\",\n            value: 8,\n            message: \"Password must be at least 8 characters long\"\n          },\n          {\n            field: \"password\",\n            operator: \"matches\",\n            value: \".*[A-Z].*\",\n            message: \"Password must contain at least one uppercase letter\"\n          },\n          {\n            field: \"password\",\n            operator: \"matches\",\n            value: \".*[0-9].*\",\n            message: \"Password must contain at least one number\"\n          }\n        ]\n      },\n\n      // Age verification\n      {\n        field: \"birthDate\",\n        operator: \"date-before\",\n        value: \"$.today - 18 years\",\n        message: \"You must be 18 or older to register\"\n      },\n\n      // Terms acceptance\n      {\n        field: \"acceptTerms\",\n        operator: \"equals\",\n        value: true,\n        message: \"You must accept our terms and conditions\"\n      },\n\n      // Optional referral code validation\n      {\n        or: [\n          { field: \"referralCode\", operator: \"not-exists\", value: true },\n          { field: \"referralCode\", operator: \"empty\", value: true },\n          {\n            and: [\n              { field: \"referralCode\", operator: \"string-length\", value: 8 },\n              { field: \"referralCode\", operator: \"alpha-numeric\", value: true }\n            ]\n          }\n        ],\n        message: \"Referral code must be 8 alphanumeric characters\"\n      }\n    ]\n  }\n};\n```\n\n## 🎨 Advanced Features\n\n### 🔗 Self-Referencing Magic\nCompare fields against other fields dynamically:\n\n```typescript\nconst budgetRule = {\n  conditions: {\n    and: [\n      // Actual cost must not exceed budget\n      {\n        field: \"$.project.actualCost\",\n        operator: \"less-than-or-equals\",\n        value: \"$.project.approvedBudget\"\n      },\n      // Start date must be before end date\n      {\n        field: \"$.project.startDate\",\n        operator: \"date-before\",\n        value: \"$.project.endDate\"\n      },\n      // Team size appropriate for project scope\n      {\n        field: \"$.project.teamSize\",\n        operator: \"greater-than-or-equals\",\n        value: \"$.project.minimumTeamSize\"\n      }\n    ]\n  }\n};\n```\n\n### 🏗️ Fluent Builder Pattern\nConstruct complex rules programmatically:\n\n```typescript\nconst complexRule = RuleEngine.builder()\n  .add({\n    and: [\n      { field: \"userType\", operator: \"equals\", value: \"premium\" },\n      { field: \"subscriptionActive\", operator: \"equals\", value: true }\n    ],\n    result: { access: \"premium\", features: [\"analytics\", \"api\", \"support\"] }\n  })\n  .add({\n    and: [\n      { field: \"userType\", operator: \"equals\", value: \"basic\" },\n      { field: \"trialExpired\", operator: \"equals\", value: false }\n    ],\n    result: { access: \"basic\", features: [\"dashboard\"] }\n  })\n  .default({ access: \"none\", features: [] })\n  .build(true); // Validate during build\n```\n\n### 🔧 Custom Operators (V2)\nExtend the engine with your own operators:\n\n```typescript\nimport { registerCustomOperator, OperatorCategory, BaseOperatorStrategy } from '@usex/rule-engine';\n\nclass CreditCardOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata = {\n    name: \"credit-card\",\n    displayName: \"Credit Card Number\",\n    category: OperatorCategory.PATTERN,\n    description: \"Validates credit card numbers using Luhn algorithm\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n  };\n\n  evaluate(context) {\n    const { fieldValue } = context;\n    return this.isValidCreditCard(fieldValue);\n  }\n\n  private isValidCreditCard(cardNumber: string): boolean {\n    // Luhn algorithm implementation\n    const digits = cardNumber.replace(/\\D/g, '');\n    let sum = 0;\n    let isEven = false;\n\n    for (let i = digits.length - 1; i >= 0; i--) {\n      let digit = parseInt(digits[i]);\n\n      if (isEven) {\n        digit *= 2;\n        if (digit > 9) digit -= 9;\n      }\n\n      sum += digit;\n      isEven = !isEven;\n    }\n\n    return sum % 10 === 0;\n  }\n}\n\n// Register and use\nregisterCustomOperator(CreditCardOperator);\n\nconst paymentRule = {\n  conditions: {\n    and: [\n      { field: \"cardNumber\", operator: \"credit-card\" },\n      { field: \"cvv\", operator: \"string-length\", value: 3 }\n    ]\n  }\n};\n```\n\n### 🎭 Data Mutations\nPreprocess data before evaluation:\n\n```typescript\nconst engine = new RuleEngine();\n\n// Add mutations for data preprocessing\nengine.addMutation('normalizeEmail', (data) => {\n  if (data.email) {\n    data.email = data.email.toLowerCase().trim();\n  }\n  return data;\n});\n\nengine.addMutation('calculateAge', (data) => {\n  if (data.birthDate) {\n    const today = new Date();\n    const birth = new Date(data.birthDate);\n    data.age = today.getFullYear() - birth.getFullYear();\n  }\n  return data;\n});\n\n// Mutations are applied automatically before evaluation\nconst result = await engine.evaluate(rule, {\n  email: \"  USER@EXAMPLE.COM  \",\n  birthDate: \"1990-01-01\"\n});\n```\n\n### 📊 Rule Introspection\nUnderstand what your rules need:\n\n```typescript\nconst insights = RuleEngine.introspect(complexRule);\nconsole.log(insights);\n// {\n//   fields: [\"userType\", \"subscriptionActive\", \"trialExpired\"],\n//   operators: [\"equals\"],\n//   possibleResults: [\n//     { access: \"premium\", features: [\"analytics\", \"api\", \"support\"] },\n//     { access: \"basic\", features: [\"dashboard\"] },\n//     { access: \"none\", features: [] }\n//   ],\n//   complexity: \"medium\",\n//   estimatedPerformance: \"fast\"\n// }\n```\n\n## 🏎️ Performance & Optimization\n\n### Real-World Benchmarks\n*Performance data from actual benchmark runs (10,000 iterations each on modern hardware)*\n\n#### Core Rule Evaluation\n| Operation | Hz (ops/sec) | Avg Time | Performance Grade |\n|-----------|-------------|----------|-------------------|\n| **Simple Rules (3-5 conditions)** | **~16,900** | **0.059ms** | **🚀 Lightning Fast** |\n| Complex Rules (nested evaluation) | ~17,400 | 0.057ms | 🔥 Blazing |\n| Complex Rules (priority-based) | ~8,000 | 0.126ms | ⚡ Very Fast |\n| Array Operations | ~45,400 | 0.022ms | 🚀 Ultra Fast |\n\n#### Advanced Features  \n| Feature | Hz (ops/sec) | Avg Time | Performance Grade |\n|---------|-------------|----------|-------------------|\n| **JSONPath Resolution (simple)** | **~55,000** | **0.018ms** | **🔥 Blazing Fast** |\n| JSONPath Deep Nested Access | ~54,000 | 0.019ms | 🔥 Blazing Fast |\n| JSONPath Array Processing | ~49,500 | 0.020ms | 🚀 Ultra Fast |\n| Self-Referencing (complex) | ~33,600 | 0.030ms | 🚀 Excellent |\n| Self-Referencing (simple) | ~30,900 | 0.032ms | 🚀 Excellent |\n\n#### Data Processing & Validation\n| Operation | Hz (ops/sec) | Avg Time | Use Case |\n|-----------|-------------|----------|----------|\n| **Rule Builder (simple)** | **~12,000,000** | **0.0001ms** | Rule Construction |\n| Rule Builder (complex) | ~94,300 | 0.011ms | Complex Rule Building |\n| Rule Validation | ~67,000 | 0.015ms | Schema Validation |\n| Data Mutations (simple) | ~16,300 | 0.061ms | Data Preprocessing |\n| Data Mutations (complex) | ~34,100 | 0.029ms | Advanced Transformations |\n| Text Interpolation | ~796,000 | 0.0013ms | Dynamic Messages |\n\n#### Error Handling & Edge Cases\n| Operation | Hz (ops/sec) | Performance Grade |\n|-----------|-------------|-------------------|\n| **Unknown Operator Handling** | **~1,661,000** | ⚡ Instant Response |\n| Invalid Ruleset Handling | ~214,000 | 🚀 Very Fast |\n| Exists/NotExists Operators | ~41,400 | 🔥 Blazing |\n\n*All benchmarks run on 10,000 iterations with statistical accuracy. Performance may vary based on hardware and rule complexity.*\n\n### Bundle Size\n| Build Type | Size |\n|------------|------|\n| Minified | 102.7kB |\n| Minified + Gzipped | **18.4kB** |\n\n*Zero dependencies = predictable bundle size with tree-shaking support*\n\n### Optimization Tips\n\n**1. Trust Mode for Validated Rules**\n```typescript\n// Skip validation for 20% performance boost\nconst result = await RuleEngine.evaluate(rule, data, true);\n```\n\n**2. Reuse Engine Instances**\n```typescript\nconst engine = new RuleEngine();\n// Reuse for better performance with mutations\n```\n\n**3. Batch Processing**\n```typescript\n// Process multiple records at once\nconst results = await RuleEngine.evaluate(rule, arrayOfData);\n```\n\n**4. Operator Selection**\n```typescript\n// Prefer specific operators over general ones\n{ operator: \"equals\" }        // ✅ Fast\n{ operator: \"matches\" }       // ⚠️ Slower for simple cases\n```\n\n## 🎓 TypeScript Support\n\nFull type safety with intelligent inference:\n\n```typescript\ninterface UserPermissions {\n  canRead: boolean;\n  canWrite: boolean;\n  canDelete: boolean;\n  level: 'admin' | 'user' | 'guest';\n}\n\n// Type-safe rule definition\nconst accessRule: Rule<UserPermissions> = {\n  conditions: [\n    {\n      and: [\n        { field: \"role\", operator: \"equals\", value: \"admin\" },\n        { field: \"active\", operator: \"equals\", value: true }\n      ],\n      result: {\n        canRead: true,\n        canWrite: true,\n        canDelete: true,\n        level: \"admin\"\n      }\n    }\n  ],\n  default: {\n    canRead: false,\n    canWrite: false,\n    canDelete: false,\n    level: \"guest\"\n  }\n};\n\n// Type-safe evaluation\nconst result = await RuleEngine.evaluate<UserPermissions>(accessRule, userData);\n// result.value is typed as UserPermissions ✅\n```\n\n### Generic Builder Pattern\n```typescript\nconst typedRule = RuleEngine.builder<UserPermissions>()\n  .add({\n    and: [{ field: \"role\", operator: \"equals\", value: \"admin\" }],\n    result: { canRead: true, canWrite: true, canDelete: true, level: \"admin\" }\n  })\n  .default({ canRead: false, canWrite: false, canDelete: false, level: \"guest\" })\n  .build();\n```\n\n## 🧪 Testing Your Rules\n\n```typescript\nimport { describe, it, expect } from 'vitest';\nimport { RuleEngine } from '@usex/rule-engine';\n\ndescribe('Discount Rules', () => {\n  it('should apply VIP discount for qualifying orders', async () => {\n    const result = await RuleEngine.evaluate(discountRule, {\n      customer: { tier: 'vip', orderCount: 5 },\n      order: { total: 150 }\n    });\n\n    expect(result.isPassed).toBe(true);\n    expect(result.value.discount).toBe(0.20);\n    expect(result.value.message).toContain('VIP');\n  });\n\n  it('should validate rule structure', () => {\n    const validation = RuleEngine.validate(discountRule);\n    expect(validation.isValid).toBe(true);\n    expect(validation.errors).toHaveLength(0);\n  });\n\n  it('should handle edge cases gracefully', async () => {\n    const result = await RuleEngine.evaluate(discountRule, {});\n    expect(result.value).toEqual({ discount: 0, message: \"No discount available\" });\n  });\n});\n```\n\n## 📚 Documentation & Resources\n\n- 📖 **[TypeScript Guide](./docs/typescript-guide.md)** - Advanced TypeScript patterns and best practices\n- 🔧 **[API Reference](./docs/api-reference-v2.md)** - Complete method documentation with examples\n- 🚀 **[Migration Guide](./docs/v2-migration-guide.md)** - Upgrading from v1 to v2\n- 🎯 **[Operators Reference](./docs/operators.md)** - Complete list of all 121+ operators\n- 💡 **[Best Practices](./docs/best-practices.md)** - Patterns for maintainable rule systems\n- 📋 **[Changelog](./CHANGELOG.md)** - Detailed version history\n\n## 🤝 Contributing\n\nWe love contributions! Whether it's:\n- 🐛 Bug reports and fixes\n- ✨ New operators or features\n- 📖 Documentation improvements\n- 🎨 Examples and tutorials\n\nSee our [Contributing Guide](../../CONTRIBUTING.md) for details.\n\n### Development Setup\n```bash\n# Clone and setup\ngit clone https://github.com/ali-master/rule-engine.git\ncd rule-engine\npnpm install\n\n# Run tests\npnpm test\n\n# Run benchmarks\npnpm test:bench\n\n# Build package\npnpm build\n\n# Watch mode for development\npnpm dev\n```\n\n## 🆚 Why Choose this lib Over Alternatives?\n\n| Feature | @usex/rule-engine | json-rules-engine | node-rules |\n|---------|-------------------|-------------------|------------|\n| Zero Dependencies | ✅ | ❌ | ❌ |\n| TypeScript Native | ✅ | ⚠️ Partial | ❌ |\n| JSONPath Support | ✅ | ❌ | ❌ |\n| Self-Referencing | ✅ | ❌ | ❌ |\n| Custom Operators | ✅ | ⚠️ Limited | ❌ |\n| Performance (ops/sec) | 17k+ (55k+ JSONPath) | 45k | 30k |\n| Bundle Size | 18.4KB | 45KB | 38KB |\n| Browser Support | ✅ | ✅ | ❌ |\n| Rule Introspection | ✅ | ❌ | ❌ |\n| Fluent Builder | ✅ | ❌ | ❌ |\n\n## 📄 License\n\nMIT © [Ali Torki](https://github.com/ali-master)\n\n---\n\n<div align=\"center\">\n\n**Built with ❤️ by [Ali Torki](https://github.com/ali-master), for developers**\n\n[⭐ Star us on GitHub](https://github.com/ali-master/rule-engine) • [🐛 Report Issues](https://github.com/ali-master/rule-engine/issues) • [💬 Discussions](https://github.com/ali-master/rule-engine/discussions)\n\n</div>\n"
  },
  {
    "path": "packages/core/benchmarks/builder.bench.ts",
    "content": "import { expect, describe, bench } from \"vitest\";\nimport { RuleEngine, Operators, ConditionTypes } from \"@root\";\n\ndescribe(\"builder correctly\", () => {\n  bench(\n    \"creates a valid ruleset\",\n    () => {\n      const builder = RuleEngine.builder();\n\n      builder\n        .add(\n          builder.condition(ConditionTypes.AND, [\n            builder.constraint(\"field\", Operators.Equals, \"value\"),\n          ]),\n        )\n        .build();\n    },\n    {\n      iterations: 10_000,\n    },\n  );\n\n  bench(\n    \"creates a complex ruleset properly\",\n    () => {\n      const builder = RuleEngine.builder();\n\n      const rule = builder\n        .add(\n          builder.condition(\n            ConditionTypes.AND,\n            [\n              builder.condition(ConditionTypes.OR, [\n                builder.constraint(\"fieldA\", Operators.Equals, \"bar\"),\n                builder.constraint(\"fieldB\", Operators.GreaterThanOrEquals, 2),\n              ]),\n              builder.constraint(\"fieldC\", Operators.NotIn, [1, 2, 3]),\n            ],\n            {\n              value: 3,\n            },\n          ),\n        )\n        .add(builder.condition(ConditionTypes.NONE, [], { value: 5 }))\n        .add(\n          builder.condition(ConditionTypes.OR, [\n            builder.constraint(\"fieldA\", Operators.Equals, \"value\"),\n          ]),\n        )\n        .default({ value: 2 })\n        .build(false);\n\n      expect(rule).toEqual({\n        conditions: [\n          {\n            and: [\n              {\n                or: [\n                  { field: \"fieldA\", operator: \"equals\", value: \"bar\" },\n                  {\n                    field: \"fieldB\",\n                    operator: \"greater-than-or-equals\",\n                    value: 2,\n                  },\n                ],\n              },\n              { field: \"fieldC\", operator: \"not-in\", value: [1, 2, 3] },\n            ],\n            result: { value: 3 },\n          },\n          { none: [], result: { value: 5 } },\n          {\n            or: [{ field: \"fieldA\", operator: \"equals\", value: \"value\" }],\n          },\n        ],\n        default: { value: 2 },\n      });\n    },\n    {\n      iterations: 10_000,\n    },\n  );\n});\n"
  },
  {
    "path": "packages/core/benchmarks/engine.bench.ts",
    "content": "import { describe, bench } from \"vitest\";\nimport type { OperatorsType } from \"@root\";\nimport { RuleEngine, Operators } from \"@root\";\n// Assets\nimport { valid1Json } from \"../test/rulesets/valid1.json\";\nimport { valid3Json } from \"../test/rulesets/valid3.json\";\nimport { valid4Json } from \"../test/rulesets/valid4.json\";\nimport { valid5Json } from \"../test/rulesets/valid5.json\";\nimport { valid13Json } from \"../test/rulesets/valid13.json\";\nimport { Valid10Json } from \"../test/rulesets/valid10.json\";\nimport { Valid11Json } from \"../test/rulesets/valid11.json\";\nimport { selfFieldsConstraintsJson } from \"../test/rulesets/self-fields-constraints.json\";\n\n// Sample data for benchmarks\nconst simpleData = {\n  payload: { ProfitPercentage: 9 },\n  WinRate: 80,\n  AverageTradeDuration: 5,\n  Duration: 9000000,\n  TotalDaysTraded: 5,\n};\n\nconst complexData = {\n  Monetization: \"Real\",\n  Leverage: 150,\n  CountryIso: \"FI\",\n  foo: \"bar\",\n  another: false,\n  countries: [\"US\", \"FR\"],\n  nested: {\n    field: \"value\",\n    array: [1, 2, 3, 4, 5],\n  },\n};\n\nconst largnestedData = {\n  user: {\n    profile: {\n      personal: {\n        name: \"John\",\n        age: 30,\n        preferences: {\n          theme: \"dark\",\n          notifications: true,\n          settings: {\n            privacy: \"public\",\n            language: \"en\",\n          },\n        },\n      },\n    },\n  },\n  orders: Array.from({ length: 50 }, (_, i) => ({\n    id: i,\n    total: Math.random() * 1000,\n    items: Array.from({ length: 5 }, (_, j) => ({\n      id: j,\n      price: Math.random() * 100,\n    })),\n  })),\n};\n\ndescribe(\"rule Engine Performance Benchmarks\", () => {\n  describe(\"simple Rules (3-5 conditions)\", () => {\n    bench(\n      \"simple rule - basic evaluation\",\n      async () => {\n        await RuleEngine.getEvaluateResult(valid1Json, simpleData);\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"simple rule - single condition\",\n      async () => {\n        await RuleEngine.getEvaluateResult(valid13Json, {}, false);\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"simple rule - different data\",\n      async () => {\n        await RuleEngine.getEvaluateResult(valid1Json, {\n          payload: { ProfitPercentage: 11 },\n        });\n      },\n      { iterations: 10_000 },\n    );\n  });\n\n  describe(\"complex Rules (10+ conditions)\", () => {\n    bench(\n      \"complex rule - nested evaluation\",\n      async () => {\n        await RuleEngine.getEvaluateResult(valid3Json, complexData);\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"complex rule - priority conditions\",\n      async () => {\n        await RuleEngine.getEvaluateResult(valid4Json, {\n          CountryIso: \"GB\",\n          Monetization: \"Real\",\n          Category: 13,\n        });\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"complex rule - array operations\",\n      async () => {\n        await RuleEngine.getEvaluateResult(valid5Json, {\n          countries: [\"US\", \"FR\"],\n        });\n      },\n      { iterations: 10_000 },\n    );\n  });\n\n  describe(\"jSONPath Resolution\", () => {\n    bench(\n      \"jSONPath - simple nested field\",\n      async () => {\n        await RuleEngine.getEvaluateResult(\n          {\n            conditions: [\n              {\n                and: [\n                  {\n                    field: \"$.foo.bar\",\n                    operator: Operators.Equals,\n                    value: \"test\",\n                  },\n                ],\n              },\n            ],\n          },\n          {\n            foo: {\n              bar: \"test\",\n            },\n          },\n        );\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"jSONPath - deep nested access\",\n      async () => {\n        await RuleEngine.getEvaluateResult(\n          {\n            conditions: [\n              {\n                and: [\n                  {\n                    field: \"$.user.profile.personal.name\",\n                    operator: Operators.Equals,\n                    value: \"John\",\n                  },\n                ],\n              },\n            ],\n          },\n          largnestedData,\n        );\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"jSONPath - array processing\",\n      async () => {\n        await RuleEngine.getEvaluateResult(\n          {\n            conditions: [\n              {\n                and: [\n                  {\n                    field: \"$.foo.bar\",\n                    operator: Operators.Equals,\n                    value: \"bar\",\n                  },\n                ],\n              },\n            ],\n          },\n          [{ foo: { bar: \"test\" } }, { foo: { bar: \"bar\" } }, {}],\n        );\n      },\n      { iterations: 10_000 },\n    );\n  });\n\n  describe(\"self-Referencing Rules\", () => {\n    bench(\n      \"self-referencing - complex validation\",\n      async () => {\n        await RuleEngine.evaluate(selfFieldsConstraintsJson, {\n          meta: {\n            default: {\n              password: \"@john-doe-@john-doe\",\n            },\n          },\n          username: \"john-doe\",\n          name: \"john\",\n          family: \"doe\",\n        });\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"self-referencing - field comparison\",\n      async () => {\n        await RuleEngine.evaluate(selfFieldsConstraintsJson, {\n          meta: {\n            default: {\n              password: \"Aa101010@\",\n            },\n          },\n          username: \"john-doe\",\n          name: \"john\",\n          family: \"doe\",\n        });\n      },\n      { iterations: 10_000 },\n    );\n  });\n\n  describe(\"special Conditions\", () => {\n    bench(\n      \"exists/NotExists operators\",\n      async () => {\n        await RuleEngine.getEvaluateResult(Valid10Json, {\n          name: \"John\",\n          age: 20,\n          family: \"Doe\",\n          relationship: \"Father\",\n        });\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"priority-based evaluation\",\n      async () => {\n        await RuleEngine.evaluate(Valid11Json, {\n          payload: {\n            depositAmount: \"3\",\n          },\n          metadata: {\n            tenantId: \"1\",\n          },\n        });\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"early termination optimization\",\n      async () => {\n        await RuleEngine.getEvaluateResult(valid4Json, {\n          Leverage: 500, // First condition match - should terminate early\n          CountryIso: \"GB\",\n          Monetization: \"Real\",\n          Category: 22,\n        });\n      },\n      { iterations: 10_000 },\n    );\n  });\n\n  describe(\"error Handling\", () => {\n    bench(\n      \"unknown operator handling\",\n      async () => {\n        await RuleEngine.getEvaluateResult(\n          {\n            conditions: [\n              {\n                and: [\n                  {\n                    field: \"name\",\n                    operator: \"foo\" as OperatorsType,\n                    value: \"test\",\n                  },\n                ],\n              },\n            ],\n          },\n          { name: \"test\" },\n          true,\n        );\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"invalid ruleset handling\",\n      async () => {\n        try {\n          await RuleEngine.getEvaluateResult({ conditions: [] }, {});\n        } catch {}\n      },\n      { iterations: 10_000 },\n    );\n  });\n});\n"
  },
  {
    "path": "packages/core/benchmarks/introspector.bench.ts",
    "content": "import { describe, bench } from \"vitest\";\nimport { RuleEngine } from \"@root\";\n// Assets\nimport { valid2Json } from \"../test/rulesets/valid2.json\";\nimport { valid6Json } from \"../test/rulesets/valid6.json\";\n\ndescribe(\"introspector correctly\", () => {\n  bench(\n    \"detects invalid rule\",\n    async () => {\n      RuleEngine.introspect(valid2Json);\n    },\n    {\n      iterations: 10_000,\n    },\n  );\n\n  bench(\n    \"introspects valid rule\",\n    async () => {\n      RuleEngine.introspect(valid6Json);\n    },\n    {\n      iterations: 10_000,\n    },\n  );\n});\n"
  },
  {
    "path": "packages/core/benchmarks/json-path.bench.ts",
    "content": "import { describe, bench } from \"vitest\";\nimport { RuleEngine, ObjectDiscovery } from \"@root\";\n// Rules\nimport { selfFieldsConstraintsJson } from \"../test/rulesets/self-fields-constraints.json\";\n\ndescribe(\"json path correctly\", () => {\n  const discovery = new ObjectDiscovery();\n  bench(\n    \"resolves simple field definitions in a Text\",\n    async () => {\n      discovery.resolveTextPathExpressions(\n        \"Password is invalid and contains username($.username), name($.name) and family($.family)\",\n        {\n          meta: {\n            default: {\n              password: \"@john-doe-@johndoe\",\n            },\n          },\n          username: \"john-doe\",\n          name: \"john\",\n          family: \"doe\",\n        },\n      );\n    },\n    {\n      iterations: 10_000,\n    },\n  );\n\n  bench(\n    \"resolves complex nested field definitions in a Text\",\n    async () => {\n      const data = {\n        store: {\n          book: [\n            {\n              category: \"reference\",\n              author: \"Nigel Rees\",\n              title: \"Sayings of the Century\",\n              price: 8.95,\n            },\n            {\n              category: \"fiction\",\n              author: \"Evelyn Waugh\",\n              title: \"Sword of Honour\",\n              price: 12.99,\n            },\n            {\n              category: \"fiction\",\n              author: \"Herman Melville\",\n              title: \"Moby Dick\",\n              isbn: \"0-553-21311-3\",\n              price: 8.99,\n            },\n            {\n              category: \"fiction\",\n              author: \"J. R. R. Tolkien\",\n              title: \"The Lord of the Rings\",\n              isbn: \"0-395-19395-8\",\n              price: 22.99,\n            },\n          ],\n          bicycle: {\n            color: \"red\",\n            price: 19.95,\n          },\n        },\n      };\n\n      const expression = \"$.store.book[*].author\";\n      discovery.resolveTextPathExpressions(`Hi all ${expression}`, data);\n    },\n    {\n      iterations: 10_000,\n    },\n  );\n\n  bench(\n    \"ruleEngine evaluate and return the resolved message correctly\",\n    async () => {\n      await RuleEngine.evaluate(selfFieldsConstraintsJson, {\n        meta: {\n          default: {\n            password: \"Aa101010@\",\n          },\n        },\n        username: \"john-doe\",\n        name: \"john\",\n        family: \"doe\",\n      });\n    },\n    {\n      iterations: 10_000,\n    },\n  );\n});\n"
  },
  {
    "path": "packages/core/benchmarks/mutator.bench.ts",
    "content": "// Utilities\nimport { describe, bench } from \"vitest\";\nimport { RuleEngine, Operators } from \"@root\";\n// Assets\nimport { valid1Json } from \"../test/rulesets/valid1.json\";\n\ndescribe(\"mutation Performance Benchmarks\", () => {\n  describe(\"data Mutations\", () => {\n    bench(\n      \"simple field mutation\",\n      async () => {\n        const rp = RuleEngine.getInstance();\n        rp.addMutation(\"WinRate\", (value: number) => value * 2);\n\n        await rp.getEvaluateResult(valid1Json, {\n          WinRate: 31,\n          AverageTradeDuration: 60,\n          Duration: 99999999,\n          TotalDaysTraded: 3,\n        });\n\n        rp.clearMutations();\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"multiple field mutations\",\n      async () => {\n        const rp = RuleEngine.getInstance();\n        rp.addMutation(\"WinRate\", (value: number) => value * 2);\n        rp.addMutation(\"AverageTradeDuration\", (value: number) => value / 2);\n\n        await rp.getEvaluateResult(valid1Json, {\n          WinRate: 31,\n          AverageTradeDuration: 60,\n          Duration: 99999999,\n          TotalDaysTraded: 3,\n        });\n\n        rp.clearMutations();\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"jSONPath nested mutation\",\n      async () => {\n        const rp = RuleEngine.getInstance();\n        rp.addMutation(\"$.foo.bar\", (value: number) => value * 2);\n\n        await rp.getEvaluateResult(\n          {\n            conditions: [\n              {\n                and: [\n                  {\n                    field: \"$.foo.bar\",\n                    operator: Operators.GreaterThan,\n                    value: 6,\n                  },\n                ],\n              },\n            ],\n          },\n          { foo: { bar: 5 } },\n        );\n\n        rp.clearMutations();\n      },\n      { iterations: 10_000 },\n    );\n\n    bench(\n      \"complex data transformation\",\n      async () => {\n        const rp = RuleEngine.getInstance();\n        rp.addMutation(\"$.user.score\", (value: number) =>\n          Math.round(value * 1.15),\n        );\n        rp.addMutation(\"$.user.level\", (value: string) => value.toUpperCase());\n\n        await rp.getEvaluateResult(\n          {\n            conditions: [\n              {\n                and: [\n                  {\n                    field: \"$.user.score\",\n                    operator: Operators.GreaterThan,\n                    value: 100,\n                  },\n                ],\n              },\n            ],\n          },\n          { user: { score: 85, level: \"premium\" } },\n        );\n\n        rp.clearMutations();\n      },\n      { iterations: 10_000 },\n    );\n  });\n});\n"
  },
  {
    "path": "packages/core/benchmarks/validator.bench.ts",
    "content": "import { describe, bench } from \"vitest\";\nimport { RuleEngine, Operators } from \"@root\";\n// Assets\nimport { valid1Json } from \"../test/rulesets/valid1.json\";\nimport { valid3Json } from \"../test/rulesets/valid3.json\";\nimport { selfFieldsConstraintsJson } from \"../test/rulesets/self-fields-constraints.json\";\n\ndescribe(\"validator correctly\", () => {\n  bench(\n    \"validates a correct rule\",\n    () => {\n      RuleEngine.validate({\n        conditions: [\n          {\n            and: [{ field: \"name\", operator: Operators.Equals, value: \"test\" }],\n          },\n        ],\n      });\n    },\n    {\n      iterations: 10_000,\n    },\n  );\n\n  bench(\n    \"validates a simple correct rule\",\n    () => {\n      RuleEngine.validate(valid1Json);\n    },\n    {\n      iterations: 10_000,\n    },\n  );\n\n  bench(\n    \"validates a simple correct self rule\",\n    () => {\n      RuleEngine.validate(selfFieldsConstraintsJson);\n    },\n    {\n      iterations: 10_000,\n    },\n  );\n\n  bench(\n    \"validates a nested correct rule\",\n    () => {\n      RuleEngine.validate(valid3Json);\n    },\n    {\n      iterations: 10_000,\n    },\n  );\n});\n"
  },
  {
    "path": "packages/core/docs/README.md",
    "content": "# Documentation Structure\n\nThis directory contains comprehensive documentation for @usex/rule-engine.\n\n## 📚 Documentation Files\n\n| File | Description | Key Topics |\n|------|-------------|------------|\n| [**index.md**](./index.md) | Documentation hub | Overview, quick links, navigation |\n| [**api-reference.md**](./api-reference.md) | Complete API documentation | Classes, methods, interfaces, types |\n| [**operators.md**](./operators.md) | All 126 operators reference | Detailed operator guide with examples |\n| [**best-practices.md**](./best-practices.md) | Production best practices | Performance, security, testing, patterns |\n| [**migration-guide.md**](./migration-guide.md) | Migration from other engines | json-rules-engine, node-rules, custom code |\n\n## 🎯 Quick Navigation\n\n### For New Users\n1. Start with the [main README](../README.md)\n2. Review [operators](./operators.md) for available operations\n3. Check [examples](../README.md#examples) for common patterns\n\n### For Developers\n1. [API Reference](./api-reference.md) for detailed method documentation\n2. [Best Practices](./best-practices.md) for production guidance\n3. [TypeScript examples](../README.md#typescript-support) for type safety\n\n### For Migration\n1. [Migration Guide](./migration-guide.md) for switching from other engines\n2. [Common patterns](./migration-guide.md#common-migration-patterns) for code conversion\n\n## 📖 Documentation Coverage\n\n### Core Concepts ✅\n- Rule structure and types\n- Conditions and constraints\n- Logical operators (and/or/none)\n- Result handling\n- Default values\n\n### API Coverage ✅\n- RuleEngine class (static & instance methods)\n- ObjectDiscovery utilities\n- Builder pattern API\n- Mutation system\n- Validation & introspection\n\n### Operators ✅\n- 126 operators documented\n- Categorized by type\n- Usage examples for each\n- Common patterns\n\n### Best Practices ✅\n- Performance optimization\n- Error handling strategies\n- Security considerations\n- Testing approaches\n- Maintenance tips\n\n### Migration Paths ✅\n- From json-rules-engine\n- From node-rules\n- From business-rules-engine\n- From custom implementations\n\n## 🔍 Finding Information\n\n### By Topic\n\n| Topic | Location |\n|-------|----------|\n| Installation | [README](../README.md#installation) |\n| Quick Start | [README](../README.md#quick-start) |\n| JSONPath Usage | [README](../README.md#jsonpath-support) |\n| Date Operations | [Operators](./operators.md#date--time-operators) |\n| Array Operations | [Operators](./operators.md#array-operators) |\n| Performance Tips | [Best Practices](./best-practices.md#performance-optimization) |\n| Testing Strategies | [Best Practices](./best-practices.md#testing-strategies) |\n| Security | [Best Practices](./best-practices.md#security-considerations) |\n\n### By Use Case\n\n| Use Case | Documentation |\n|----------|---------------|\n| Form Validation | [Examples](../README.md#form-validation-rules) |\n| Access Control | [Examples](../README.md#access-control-rules) |\n| Discount Rules | [Examples](../README.md#e-commerce-discount-rules) |\n| Complex Conditions | [Best Practices](./best-practices.md#rule-design) |\n| Batch Processing | [API Reference](./api-reference.md#evaluate) |\n\n## 💡 Tips for Reading\n\n1. **Start Simple**: Begin with basic examples and gradually explore advanced features\n2. **Use Search**: Use your editor's search to find specific operators or methods\n3. **Check Examples**: Most concepts include practical examples\n4. **Follow Links**: Documentation is interconnected for easy navigation\n5. **Try It Out**: Best way to learn is to experiment with the code\n\n## 🤝 Contributing to Docs\n\nSee [CONTRIBUTING.md](../../../CONTRIBUTING.md) for guidelines on improving documentation.\n\n---\n\nGenerated with ❤️ for the @usex/rule-engine community"
  },
  {
    "path": "packages/core/docs/api-reference-v2.md",
    "content": "# API Reference v2.1\n\nComplete API reference for @usex/rule-engine v2.1 with enhanced TypeScript support.\n\n## Table of Contents\n\n- [RuleEngine Class](#ruleengine-class)\n- [Evaluator Class](#evaluator-class)\n- [ObjectDiscovery Class](#objectdiscovery-class)\n- [Mutator Class](#mutator-class)\n- [Types and Interfaces](#types-and-interfaces)\n- [Operators](#operators)\n\n## RuleEngine Class\n\nThe main class for rule evaluation. Uses singleton pattern for instance management.\n\n### Getting an Instance\n\n```typescript\nconst engine = RuleEngine.getInstance(config?: RuleEngineConfig);\n```\n\n### Configuration Options\n\n```typescript\ninterface RuleEngineConfig {\n  trustMode?: boolean;              // Skip validation for performance\n  autoInitializeOperators?: boolean; // Auto-register built-in operators\n  customOperatorInit?: () => void;   // Custom initialization function\n  enableOptimizations?: boolean;     // Enable performance optimizations\n  enableCaching?: boolean;          // Cache evaluation results\n  maxCacheSize?: number;            // Maximum cache entries\n}\n```\n\n### Instance Methods\n\n#### evaluate\n\nEvaluates a rule against criteria with automatic type inference.\n\n```typescript\n// Overload 1: Single criteria object\nevaluate<T = any>(\n  rule: RuleType,\n  criteria: CriteriaObject<T>,\n  trustRule?: boolean\n): Promise<EvaluationResult<T>>\n\n// Overload 2: Array of criteria\nevaluate<T = any>(\n  rule: RuleType,\n  criteria: Array<T>,\n  trustRule?: boolean\n): Promise<Array<EvaluationResult<T>>>\n\n// Example usage\nconst singleResult = await engine.evaluate(rule, { age: 25 });\n// TypeScript knows: singleResult is EvaluationResult<T>\n\nconst arrayResults = await engine.evaluate(rule, [{ age: 25 }, { age: 30 }]);\n// TypeScript knows: arrayResults is Array<EvaluationResult<T>>\n```\n\n#### checkIsPassed\n\nQuick check if a rule passes, with optimized return types.\n\n```typescript\n// Overload 1: Single criteria\ncheckIsPassed(\n  rule: RuleType,\n  criteria: CriteriaObject,\n  trustRule?: boolean\n): Promise<boolean>\n\n// Overload 2: Array of criteria\ncheckIsPassed<T = any>(\n  rule: RuleType,\n  criteria: Array<T>,\n  trustRule?: boolean\n): Promise<boolean | boolean[]>\n\n// Example\nconst passed = await engine.checkIsPassed(rule, { age: 25 }); // boolean\nconst allPassed = await engine.checkIsPassed(rule, [{ age: 25 }, { age: 16 }]); // boolean | boolean[]\n```\n\n#### getEvaluateResult\n\nGet just the evaluation result value without metadata.\n\n```typescript\n// Overload 1: Single criteria\ngetEvaluateResult<T = any>(\n  rule: RuleType,\n  criteria: CriteriaObject,\n  trustRule?: boolean\n): Promise<T>\n\n// Overload 2: Array of criteria\ngetEvaluateResult<T = any>(\n  rule: RuleType,\n  criteria: Array<any>,\n  trustRule?: boolean\n): Promise<T[]>\n\n// Example\nconst value = await engine.getEvaluateResult<number>(rule, { score: 100 }); // number\nconst values = await engine.getEvaluateResult<number>(rule, [{ score: 100 }]); // number[]\n```\n\n#### evaluateMany\n\nEvaluate multiple rules against the same criteria.\n\n```typescript\n// Overload 1: Single criteria\nevaluateMany<T = any>(\n  rules: RuleType[],\n  criteria: CriteriaObject<T>,\n  trustRule?: boolean\n): Promise<Array<EvaluationResult<T>>>\n\n// Overload 2: Array of criteria\nevaluateMany<T = any>(\n  rules: RuleType[],\n  criteria: Array<T>,\n  trustRule?: boolean\n): Promise<Array<Array<EvaluationResult<T>>>>\n\n// Example\nconst results = await engine.evaluateMany([rule1, rule2], { age: 25 });\n// Array<EvaluationResult<T>> - one result per rule\n```\n\n#### Mutation Methods\n\n```typescript\n// Add a mutation\naddMutation(field: string, mutation: MutationFunction): void\n\n// Remove a specific mutation\nremoveMutation(field: string): void\n\n// Clear all mutations (v2.1: now removes mutations, not just cache)\nclearMutations(): void\n\n// Clear mutation cache only\nclearMutationCache(field?: string): void\n\n// Clear evaluation cache\nclearCache(): void\n```\n\n#### Introspection Methods\n\n```typescript\n// Introspect a rule with enhanced options\nintrospect<R = any>(\n  rule: RuleType<R>,\n  options?: {\n    includeMetadata?: boolean;\n    includeComplexity?: boolean;\n    validateOperators?: boolean;\n  }\n): EnhancedIntrospectionResult<R>\n\n// Validate operators in a rule\nvalidateOperators(rule: RuleType): ValidationResult\n\n// Get all operators used in a rule\ngetUsedOperators(rule: RuleType): Set<string>\n```\n\n### Static Methods\n\nAll instance methods are also available as static methods:\n\n```typescript\n// Static evaluate with overloads\nstatic evaluate<T = any>(\n  rule: RuleType,\n  criteria: CriteriaObject<T>,\n  trustRule?: boolean\n): Promise<EvaluationResult<T>>\n\nstatic evaluate<T = any>(\n  rule: RuleType,\n  criteria: Array<T>,\n  trustRule?: boolean\n): Promise<Array<EvaluationResult<T>>>\n\n// Static checkIsPassed with overloads\nstatic checkIsPassed(\n  rule: RuleType,\n  criteria: CriteriaObject,\n  trustRule?: boolean\n): Promise<boolean>\n\nstatic checkIsPassed<T = any>(\n  rule: RuleType,\n  criteria: Array<T>,\n  trustRule?: boolean\n): Promise<boolean | boolean[]>\n\n// Static getEvaluateResult with overloads\nstatic getEvaluateResult<T = any>(\n  rule: RuleType,\n  criteria: CriteriaObject,\n  trustRule?: boolean\n): Promise<T>\n\nstatic getEvaluateResult<T = any>(\n  rule: RuleType,\n  criteria: Array<any>,\n  trustRule?: boolean\n): Promise<T[]>\n```\n\n## Evaluator Class\n\nLow-level evaluation engine used internally by RuleEngine.\n\n### Methods\n\n#### evaluate\n\n```typescript\n// Overload 1: Single criteria\nevaluate(\n  rule: RuleType,\n  criteria: CriteriaObject<T>\n): EvaluationResult<T>\n\n// Overload 2: Array of criteria\nevaluate(\n  rule: RuleType,\n  criteria: Array<T>\n): Array<EvaluationResult<T>>\n```\n\n## ObjectDiscovery Class\n\nUtility class for JSONPath operations and property resolution.\n\n### Methods with Overloads\n\n#### resolveProperty\n\n```typescript\n// Overload 1: Single object\nresolveProperty(path: string, json: CriteriaObject<T>): any\n\n// Overload 2: Array\nresolveProperty(path: string, json: Array<T>): any\n\n// Example\nconst value = discovery.resolveProperty(\"$.user.name\", { user: { name: \"John\" } });\n```\n\n#### updateProperty\n\n```typescript\n// Overload 1: Single object\nupdateProperty(path: string, json: CriteriaObject<T>, value: any): any\n\n// Overload 2: Array\nupdateProperty(path: string, json: Array<T>, value: any): any\n\n// Example\ndiscovery.updateProperty(\"$.user.active\", userData, true);\n```\n\n#### resolveTextPathExpressions\n\n```typescript\n// Overload 1: Single object\nresolveTextPathExpressions(str: string, criteria: CriteriaObject<T>): string\n\n// Overload 2: Array\nresolveTextPathExpressions(str: string, criteria: Array<T>): string\n\n// Example\nconst message = discovery.resolveTextPathExpressions(\n  \"Hello $.name, your score is $.score\",\n  { name: \"John\", score: 100 }\n);\n// Result: \"Hello John, your score is 100\"\n```\n\n## Mutator Class\n\nHandles data mutations before rule evaluation.\n\n### Key Methods\n\n```typescript\n// Add a mutation\nadd(name: string, mutation: MutationFunction): void\n\n// Remove mutation(s)\nremove(names: string | string[]): void\n\n// Remove all mutations (v2.1: new method)\nremoveAll(): void\n\n// Clear cache\nclearCache(name?: string): void\n\n// Mutate data (handles both objects and arrays automatically)\nmutate(criteria: Criteria): Promise<Criteria>\n```\n\n## Types and Interfaces\n\n### Core Types\n\n```typescript\n// Criteria types\ntype CriteriaObject<T = any> = Record<string, T>;\ntype Criteria<T = any> = CriteriaObject<T> | Array<T>;\n\n// Rule types\ninterface RuleType<R = any> {\n  conditions: Condition<R> | Array<Condition<R>>;\n  default?: EngineResult<R>;\n}\n\n// Evaluation result\ninterface EvaluationResult<T = any> {\n  value: T;\n  isPassed: boolean;\n  message?: string;\n}\n\n// Condition types\ninterface Condition<R = any> {\n  or?: Array<Constraint | Condition<R>>;\n  and?: Array<Constraint | Condition<R>>;\n  none?: Array<Constraint | Condition<R>>;\n  result?: EngineResult<R>;\n}\n\n// Constraint type\ninterface Constraint {\n  field: string;\n  operator: OperatorsType;\n  value?: any;\n  message?: string;\n}\n```\n\n### Operator Types\n\n```typescript\n// Base operator strategy\nabstract class BaseOperatorStrategy<TField = any, TConstraint = any> {\n  abstract readonly metadata: OperatorMetadata;\n  abstract evaluate(context: OperatorContext): boolean;\n  abstract isValidFieldType(value: unknown): value is TField;\n  abstract isValidConstraintType(value: unknown): value is TConstraint;\n  \n  // Optional overrides\n  validate?(context: OperatorContext): ValidationResult;\n  formatMessage?(template: string, context: OperatorContext): string;\n}\n\n// Operator context\ninterface OperatorContext {\n  fieldValue: any;\n  constraintValue: any;\n  criteria: Criteria;\n  fieldPath: string;\n}\n\n// Operator metadata\ninterface OperatorMetadata {\n  name: string;\n  displayName: string;\n  category: OperatorCategory;\n  description: string;\n  acceptedFieldTypes: FieldType[];\n  expectedValueType: ValueType;\n  requiresValue: boolean;\n  isNegatable?: boolean;\n  example: string;\n}\n```\n\n## Best Practices\n\n1. **Use TypeScript generics** for type-safe results:\n   ```typescript\n   const result = await engine.evaluate<MyResultType>(rule, criteria);\n   ```\n\n2. **Leverage overloads** for better type inference:\n   ```typescript\n   // Let TypeScript infer based on input\n   const result = await engine.evaluate(rule, { age: 25 }); // Single result\n   const results = await engine.evaluate(rule, [{ age: 25 }]); // Array result\n   ```\n\n3. **Use singleton pattern** for resource efficiency:\n   ```typescript\n   const engine = RuleEngine.getInstance(); // Reuses existing instance\n   ```\n\n4. **Clean up in tests** to avoid state pollution:\n   ```typescript\n   afterEach(() => {\n     const engine = RuleEngine.getInstance();\n     engine.clearMutations();\n     engine.clearCache();\n   });\n   ```\n\n5. **Enable caching** for performance:\n   ```typescript\n   const engine = RuleEngine.getInstance({\n     enableCaching: true,\n     maxCacheSize: 1000\n   });\n   ```"
  },
  {
    "path": "packages/core/docs/api-reference.md",
    "content": "# API Reference\n\nComplete API documentation for @usex/rule-engine.\n\n## Table of Contents\n\n- [RuleEngine Class](#ruleengine-class)\n- [ObjectDiscovery Service](#objectdiscovery-service)\n- [Builder API](#builder-api)\n- [Types & Interfaces](#types--interfaces)\n- [Enums](#enums)\n- [Utilities](#utilities)\n\n## RuleEngine Class\n\nThe main class for rule evaluation and management.\n\n### Constructor\n\n```typescript\nnew RuleEngine(options?: RuleEngineOptions)\n```\n\n#### Options\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `logger` | `Logger` | `console` | Custom logger implementation |\n| `cache` | `boolean` | `true` | Enable/disable mutation caching |\n| `mutations` | `Map<string, MutationFunction>` | `new Map()` | Initial mutations |\n\n### Instance Methods\n\n#### evaluate\n\nEvaluates a rule against criteria.\n\n```typescript\nasync evaluate<R = any>(\n  rule: RuleType<R>,\n  criteria: any | any[],\n  trustRule?: boolean\n): Promise<EvaluationResult<R> | EvaluationResult<R>[]>\n```\n\n**Parameters:**\n- `rule`: The rule to evaluate\n- `criteria`: Single object or array of objects to evaluate against\n- `trustRule`: Skip rule validation if true (default: false)\n\n**Returns:**\n- Single `EvaluationResult` for single criteria\n- Array of `EvaluationResult` for array criteria\n\n**Example:**\n```typescript\nconst engine = new RuleEngine();\nconst result = await engine.evaluate(rule, { age: 25 });\n// { value: true, isPassed: true }\n```\n\n#### checkIsPassed\n\nSimple boolean check if rule passes.\n\n```typescript\nasync checkIsPassed(\n  rule: RuleType<any>,\n  criteria: any | any[],\n  trustRule?: boolean\n): Promise<boolean>\n```\n\n**Parameters:**\n- Same as `evaluate`\n\n**Returns:**\n- `true` if rule passes, `false` otherwise\n\n**Example:**\n```typescript\nconst passed = await engine.checkIsPassed(rule, { age: 25 });\n// true\n```\n\n#### getEvaluateResult\n\nGet only result values without evaluation metadata.\n\n```typescript\nasync getEvaluateResult<R = any>(\n  rule: RuleType<R>,\n  criteria: any | any[],\n  trustRule?: boolean\n): Promise<R | R[]>\n```\n\n**Parameters:**\n- Same as `evaluate`\n\n**Returns:**\n- Result value(s) only, without `isPassed` flag\n\n**Example:**\n```typescript\nconst result = await engine.getEvaluateResult(rule, data);\n// { discount: 0.15, message: \"15% off\" }\n```\n\n#### evaluateMany\n\nEvaluate multiple rules against same criteria.\n\n```typescript\nasync evaluateMany<R = any>(\n  rules: RuleType<R>[],\n  criteria: any,\n  trustRule?: boolean\n): Promise<EvaluationResult<R>[]>\n```\n\n**Parameters:**\n- `rules`: Array of rules to evaluate\n- `criteria`: Single criteria object\n- `trustRule`: Skip validation for all rules\n\n**Returns:**\n- Array of evaluation results\n\n**Example:**\n```typescript\nconst results = await engine.evaluateMany([rule1, rule2], data);\n// [{ value: true, isPassed: true }, { value: false, isPassed: false }]\n```\n\n#### validate\n\nValidates rule structure.\n\n```typescript\nvalidate(rule: RuleType<any>): ValidationResult\n```\n\n**Parameters:**\n- `rule`: Rule to validate\n\n**Returns:**\n```typescript\ninterface ValidationResult {\n  isValid: boolean;\n  error?: {\n    message: string;\n    path?: string;\n    details?: any;\n  };\n}\n```\n\n**Example:**\n```typescript\nconst validation = engine.validate(rule);\nif (!validation.isValid) {\n  console.error(validation.error.message);\n}\n```\n\n#### introspect\n\nAnalyzes rule for possible input ranges.\n\n```typescript\nintrospect(rule: RuleType<any>): IntrospectionResult\n```\n\n**Parameters:**\n- `rule`: Rule to analyze\n\n**Returns:**\n```typescript\ninterface IntrospectionResult {\n  possibleCriteria: any[];\n  fields: string[];\n  operators: string[];\n  constraints: ConstraintInfo[];\n}\n```\n\n**Example:**\n```typescript\nconst analysis = engine.introspect(rule);\nconsole.log(analysis.fields); // [\"age\", \"country\"]\n```\n\n#### builder\n\nGet a new rule builder instance.\n\n```typescript\nbuilder(): RuleBuilder\n```\n\n**Returns:**\n- New `RuleBuilder` instance\n\n**Example:**\n```typescript\nconst builder = engine.builder();\nconst rule = builder\n  .add({ and: [...] })\n  .default({ value: false })\n  .build();\n```\n\n### Mutation Methods\n\n#### addMutation\n\nAdd a criteria preprocessor.\n\n```typescript\naddMutation(name: string, fn: MutationFunction): void\n```\n\n**Parameters:**\n- `name`: Unique mutation name\n- `fn`: Function that transforms criteria\n\n**Example:**\n```typescript\nengine.addMutation('normalize', (criteria) => {\n  if (criteria.email) {\n    criteria.email = criteria.email.toLowerCase();\n  }\n  return criteria;\n});\n```\n\n#### removeMutation\n\nRemove a mutation by name.\n\n```typescript\nremoveMutation(name: string): boolean\n```\n\n**Parameters:**\n- `name`: Mutation name to remove\n\n**Returns:**\n- `true` if removed, `false` if not found\n\n#### clearMutationCache\n\nClear mutation result cache.\n\n```typescript\nclearMutationCache(name?: string): void\n```\n\n**Parameters:**\n- `name`: Optional specific mutation to clear (clears all if omitted)\n\n### Static Methods\n\nAll instance methods are available as static methods on the `RuleEngine` class:\n\n```typescript\nRuleEngine.evaluate(rule, criteria, trustRule?)\nRuleEngine.checkIsPassed(rule, criteria, trustRule?)\nRuleEngine.getEvaluateResult(rule, criteria, trustRule?)\nRuleEngine.evaluateMany(rules, criteria, trustRule?)\nRuleEngine.validate(rule)\nRuleEngine.introspect(rule)\nRuleEngine.builder()\n```\n\n## ObjectDiscovery Service\n\nUtilities for working with objects and JSONPath expressions.\n\n### resolveProperty\n\nResolves a property value from an object using path or JSONPath.\n\n```typescript\nstatic resolveProperty(\n  path: string,\n  json: any\n): any\n```\n\n**Parameters:**\n- `path`: Property path or JSONPath expression\n- `json`: Object to resolve from\n\n**Returns:**\n- Resolved value or undefined\n\n**Example:**\n```typescript\nconst value = ObjectDiscovery.resolveProperty(\"$.user.profile.age\", data);\n// 25\n```\n\n### updateProperty\n\nUpdates a property value in an object.\n\n```typescript\nstatic updateProperty(\n  path: string,\n  json: any,\n  value: any\n): void\n```\n\n**Parameters:**\n- `path`: Property path or JSONPath expression\n- `json`: Object to update\n- `value`: New value to set\n\n**Example:**\n```typescript\nObjectDiscovery.updateProperty(\"$.user.age\", data, 26);\n```\n\n### resolveTextPathExpressions\n\nResolves JSONPath expressions in template strings.\n\n```typescript\nstatic resolveTextPathExpressions(\n  text: string,\n  criteria: any\n): string\n```\n\n**Parameters:**\n- `text`: Template string with JSONPath expressions\n- `criteria`: Data object for resolution\n\n**Returns:**\n- Resolved string\n\n**Example:**\n```typescript\nconst result = ObjectDiscovery.resolveTextPathExpressions(\n  \"Hello $.user.name, you have $.points points\",\n  { user: { name: \"John\" }, points: 100 }\n);\n// \"Hello John, you have 100 points\"\n```\n\n### Type Guards\n\n#### isCondition\n\nCheck if object is a valid condition.\n\n```typescript\nstatic isCondition(obj: any): obj is Condition\n```\n\n**Example:**\n```typescript\nif (ObjectDiscovery.isCondition(obj)) {\n  // obj is typed as Condition\n}\n```\n\n#### isConstraint\n\nCheck if object is a valid constraint.\n\n```typescript\nstatic isConstraint(obj: any): obj is Constraint\n```\n\n**Example:**\n```typescript\nif (ObjectDiscovery.isConstraint(obj)) {\n  // obj is typed as Constraint\n}\n```\n\n#### isGranular\n\nCheck if rule has result values.\n\n```typescript\nstatic isGranular(rule: RuleType<any>): boolean\n```\n\n**Example:**\n```typescript\nif (ObjectDiscovery.isGranular(rule)) {\n  // Rule has result values in conditions\n}\n```\n\n## Builder API\n\nFluent API for constructing rules programmatically.\n\n### Methods\n\n#### add\n\nAdd a condition to the rule.\n\n```typescript\nadd(condition: Condition<R>): RuleBuilder<R>\n```\n\n**Example:**\n```typescript\nbuilder.add({\n  and: [\n    { field: \"age\", operator: \"greater-than\", value: 18 }\n  ],\n  result: { allowed: true }\n})\n```\n\n#### default\n\nSet default result.\n\n```typescript\ndefault(result: R): RuleBuilder<R>\n```\n\n**Example:**\n```typescript\nbuilder.default({ allowed: false })\n```\n\n#### build\n\nBuild the final rule.\n\n```typescript\nbuild(validate?: boolean): RuleType<R>\n```\n\n**Parameters:**\n- `validate`: Validate rule before returning (default: false)\n\n**Returns:**\n- Complete rule object\n\n**Example:**\n```typescript\nconst rule = builder.build(true); // Validates before returning\n```\n\n### Complete Example\n\n```typescript\nconst rule = RuleEngine.builder()\n  .add({\n    and: [\n      { field: \"age\", operator: \"greater-than\", value: 21 },\n      { field: \"country\", operator: \"equals\", value: \"US\" }\n    ],\n    result: { canDrink: true }\n  })\n  .add({\n    and: [\n      { field: \"age\", operator: \"greater-than\", value: 18 },\n      { field: \"country\", operator: \"not-equals\", value: \"US\" }\n    ],\n    result: { canDrink: true }\n  })\n  .default({ canDrink: false })\n  .build(true);\n```\n\n## Types & Interfaces\n\n### RuleType\n\nMain rule structure.\n\n```typescript\ninterface RuleType<R = any> {\n  conditions: Condition<R> | Condition<R>[];\n  default?: R;\n}\n```\n\n### Condition\n\nLogical grouping of constraints.\n\n```typescript\ninterface Condition<R = any> {\n  or?: Array<Constraint | Condition<R>>;\n  and?: Array<Constraint | Condition<R>>;\n  none?: Array<Constraint | Condition<R>>;\n  result?: R;\n}\n```\n\n### Constraint\n\nBasic evaluation unit.\n\n```typescript\ninterface Constraint {\n  field: string;\n  operator: string;\n  value: any;\n  message?: string;\n}\n```\n\n### EvaluationResult\n\nResult of rule evaluation.\n\n```typescript\ninterface EvaluationResult<T = any> {\n  value: T;\n  isPassed: boolean;\n  message?: string;\n}\n```\n\n### ValidationResult\n\nResult of rule validation.\n\n```typescript\ninterface ValidationResult {\n  isValid: boolean;\n  error?: {\n    message: string;\n    path?: string;\n    details?: any;\n  };\n}\n```\n\n### IntrospectionResult\n\nResult of rule introspection.\n\n```typescript\ninterface IntrospectionResult {\n  possibleCriteria: any[];\n  fields: string[];\n  operators: string[];\n  constraints: Array<{\n    field: string;\n    operator: string;\n    value: any;\n    path: string;\n  }>;\n}\n```\n\n## Enums\n\n### ConditionType\n\n```typescript\nenum ConditionType {\n  Or = \"or\",\n  And = \"and\",\n  None = \"none\"\n}\n```\n\n### Operators\n\nSee [Operators Documentation](./operators.md) for complete list.\n\n## Utilities\n\n### Error Handling\n\n```typescript\nclass RuleEngineError extends Error {\n  constructor(message: string, public code?: string, public details?: any)\n}\n```\n\n### Date Utilities\n\n```typescript\n// Parse various date formats\nparseDate(value: any): Date\n\n// Format date to ISO string\nformatDate(date: Date): string\n\n// Check if valid date\nisValidDate(value: any): boolean\n```\n\n### Type Checking\n\n```typescript\n// Check if value is object\nisObject(value: any): boolean\n\n// Check if value is empty\nisEmpty(value: any): boolean\n\n// Deep clone object\ndeepClone<T>(obj: T): T\n```\n\n---\n\nFor more information, see the [main documentation](../README.md).\n"
  },
  {
    "path": "packages/core/docs/best-practices.md",
    "content": "# Best Practices Guide\n\nThis guide covers best practices for using @usex/rule-engine effectively in production environments.\n\n## Table of Contents\n\n- [Rule Design](#rule-design)\n- [Performance Optimization](#performance-optimization)\n- [Error Handling](#error-handling)\n- [Testing Strategies](#testing-strategies)\n- [Security Considerations](#security-considerations)\n- [Maintenance & Documentation](#maintenance--documentation)\n- [Common Pitfalls](#common-pitfalls)\n\n## Rule Design\n\n### 1. Keep Rules Simple and Focused\n\n**✅ Good: Single Responsibility**\n```typescript\n// Separate rules for different concerns\nconst ageVerificationRule = {\n  conditions: {\n    and: [\n      { field: \"age\", operator: \"greater-than-or-equals\", value: 18 },\n      { field: \"age\", operator: \"less-than\", value: 120 }\n    ]\n  }\n};\n\nconst locationRule = {\n  conditions: {\n    or: [\n      { field: \"country\", operator: \"equals\", value: \"US\" },\n      { field: \"country\", operator: \"equals\", value: \"CA\" }\n    ]\n  }\n};\n```\n\n**❌ Bad: Mixed Concerns**\n```typescript\nconst complexRule = {\n  conditions: {\n    and: [\n      { field: \"age\", operator: \"greater-than\", value: 18 },\n      { field: \"country\", operator: \"equals\", value: \"US\" },\n      { field: \"email\", operator: \"email\", value: true },\n      { field: \"subscription\", operator: \"equals\", value: \"active\" }\n    ]\n  }\n};\n```\n\n### 2. Use Meaningful Field Names\n\n**✅ Good: Clear Field Names**\n```typescript\n{\n  field: \"$.user.subscription.status\",\n  operator: \"equals\",\n  value: \"active\"\n}\n```\n\n**❌ Bad: Ambiguous Names**\n```typescript\n{\n  field: \"$.data.s\",\n  operator: \"equals\",\n  value: 1\n}\n```\n\n### 3. Leverage JSONPath for Nested Data\n\n**✅ Good: JSONPath for Deep Access**\n```typescript\n{\n  conditions: {\n    and: [\n      { field: \"$.order.items[0].quantity\", operator: \"greater-than\", value: 0 },\n      { field: \"$.customer.addresses[?(@.type=='shipping')].country\", operator: \"equals\", value: \"US\" }\n    ]\n  }\n}\n```\n\n### 4. Structure Rules for Reusability\n\n**✅ Good: Modular Rules**\n```typescript\nconst isPremiumCustomer = {\n  or: [\n    { field: \"$.customer.tier\", operator: \"equals\", value: \"premium\" },\n    { field: \"$.customer.totalSpent\", operator: \"greater-than\", value: 10000 }\n  ]\n};\n\nconst discountRule = {\n  conditions: [{\n    and: [isPremiumCustomer, { field: \"$.order.total\", operator: \"greater-than\", value: 100 }],\n    result: { discount: 0.20 }\n  }]\n};\n```\n\n### 5. Use Appropriate Operators\n\n| Use Case | Recommended Operator | Example |\n|----------|---------------------|---------|\n| Exact match | `equals` | `{ operator: \"equals\", value: \"active\" }` |\n| Text search | `like` | `{ operator: \"like\", value: \"admin\" }` |\n| Pattern match | `matches` | `{ operator: \"matches\", value: \"^[A-Z]{2}\\\\d{4}$\" }` |\n| Range check | `between` | `{ operator: \"between\", value: [10, 100] }` |\n| Null check | `null-or-undefined` | `{ operator: \"null-or-undefined\", value: true }` |\n\n## Performance Optimization\n\n### 1. Order Conditions by Likelihood of Failure\n\nPlace conditions most likely to fail first to short-circuit evaluation:\n\n**✅ Good: Fail-fast Ordering**\n```typescript\n{\n  conditions: {\n    and: [\n      // Most likely to fail first\n      { field: \"isPremium\", operator: \"equals\", value: true },\n      { field: \"age\", operator: \"greater-than\", value: 18 },\n      // Expensive operation last\n      { field: \"history\", operator: \"matches\", value: \"complex.*regex\" }\n    ]\n  }\n}\n```\n\n### 2. Use Trust Mode for Validated Rules\n\nSkip validation for rules that are known to be valid:\n\n```typescript\n// First time: validate\nconst isValid = RuleEngine.validate(rule).isValid;\n\n// Subsequent evaluations: trust mode\nif (isValid) {\n  const result = await RuleEngine.evaluate(rule, data, true); // Skip validation\n}\n```\n\n### 3. Batch Operations\n\nProcess multiple items in a single call:\n\n**✅ Good: Batch Processing**\n```typescript\nconst results = await RuleEngine.evaluate(rule, arrayOfUsers);\n```\n\n**❌ Bad: Individual Processing**\n```typescript\nconst results = [];\nfor (const user of arrayOfUsers) {\n  results.push(await RuleEngine.evaluate(rule, user));\n}\n```\n\n### 4. Cache Rule Instances\n\n**✅ Good: Reuse Parsed Rules**\n```typescript\nclass RuleService {\n  private ruleCache = new Map<string, RuleType>();\n  \n  getRule(name: string): RuleType {\n    if (!this.ruleCache.has(name)) {\n      this.ruleCache.set(name, this.loadRule(name));\n    }\n    return this.ruleCache.get(name)!;\n  }\n}\n```\n\n### 5. Use Mutations for Common Transformations\n\n```typescript\nconst engine = new RuleEngine();\n\n// Add common data transformations\nengine.addMutation('normalize', (criteria) => {\n  // Normalize common fields once\n  if (criteria.email) {\n    criteria.email = criteria.email.toLowerCase().trim();\n  }\n  if (criteria.phone) {\n    criteria.phone = criteria.phone.replace(/\\D/g, '');\n  }\n  return criteria;\n});\n```\n\n## Error Handling\n\n### 1. Validate Rules Before Production\n\n```typescript\nfunction deployRule(rule: RuleType): void {\n  const validation = RuleEngine.validate(rule);\n  \n  if (!validation.isValid) {\n    throw new Error(`Invalid rule: ${validation.error.message}`);\n  }\n  \n  // Deploy validated rule\n  saveRuleToDatabase(rule);\n}\n```\n\n### 2. Handle Evaluation Errors Gracefully\n\n```typescript\nasync function safeEvaluate(rule: RuleType, data: any): Promise<EvaluationResult> {\n  try {\n    return await RuleEngine.evaluate(rule, data);\n  } catch (error) {\n    // Log error for debugging\n    console.error('Rule evaluation failed:', error);\n    \n    // Return safe default\n    return {\n      value: rule.default || false,\n      isPassed: false,\n      message: 'Evaluation error - using default'\n    };\n  }\n}\n```\n\n### 3. Provide Meaningful Error Messages\n\n```typescript\n{\n  conditions: {\n    and: [\n      {\n        field: \"email\",\n        operator: \"email\",\n        value: true,\n        message: \"Please enter a valid email address (e.g., user@example.com)\"\n      },\n      {\n        field: \"age\",\n        operator: \"between\",\n        value: [18, 120],\n        message: \"Age must be between 18 and 120 years\"\n      }\n    ]\n  }\n}\n```\n\n## Testing Strategies\n\n### 1. Unit Test Individual Rules\n\n```typescript\ndescribe('DiscountRule', () => {\n  const rule = {\n    conditions: [{\n      and: [\n        { field: \"tier\", operator: \"equals\", value: \"gold\" },\n        { field: \"total\", operator: \"greater-than\", value: 100 }\n      ],\n      result: { discount: 0.15 }\n    }],\n    default: { discount: 0 }\n  };\n\n  test('applies discount for gold tier with qualifying total', async () => {\n    const result = await RuleEngine.evaluate(rule, {\n      tier: \"gold\",\n      total: 150\n    });\n    \n    expect(result.value.discount).toBe(0.15);\n    expect(result.isPassed).toBe(true);\n  });\n\n  test('no discount for non-qualifying orders', async () => {\n    const result = await RuleEngine.evaluate(rule, {\n      tier: \"silver\",\n      total: 150\n    });\n    \n    expect(result.value.discount).toBe(0);\n    expect(result.isPassed).toBe(true); // Default was applied\n  });\n});\n```\n\n### 2. Test Edge Cases\n\n```typescript\ndescribe('Edge Cases', () => {\n  test('handles null values', async () => {\n    const rule = {\n      conditions: {\n        and: [\n          { field: \"name\", operator: \"not-null-or-undefined\", value: true }\n        ]\n      }\n    };\n    \n    const result = await RuleEngine.evaluate(rule, { name: null });\n    expect(result.isPassed).toBe(false);\n  });\n\n  test('handles missing fields', async () => {\n    const rule = {\n      conditions: {\n        and: [\n          { field: \"$.optional.field\", operator: \"exists\", value: false }\n        ]\n      }\n    };\n    \n    const result = await RuleEngine.evaluate(rule, {});\n    expect(result.isPassed).toBe(true);\n  });\n});\n```\n\n### 3. Use Rule Introspection for Test Generation\n\n```typescript\nfunction generateTestCases(rule: RuleType) {\n  const introspection = RuleEngine.introspect(rule);\n  \n  return introspection.constraints.map(constraint => ({\n    description: `Test ${constraint.field} ${constraint.operator}`,\n    field: constraint.field,\n    validValue: generateValidValue(constraint),\n    invalidValue: generateInvalidValue(constraint)\n  }));\n}\n```\n\n## Security Considerations\n\n### 1. Validate Input Data\n\n```typescript\nconst sanitizeInput = (data: any): any => {\n  // Remove potentially dangerous fields\n  const { __proto__, constructor, prototype, ...safe } = data;\n  return safe;\n};\n\nconst result = await RuleEngine.evaluate(rule, sanitizeInput(userInput));\n```\n\n### 2. Limit Rule Complexity\n\n```typescript\nfunction validateRuleComplexity(rule: RuleType): void {\n  const maxDepth = 5;\n  const maxConditions = 50;\n  \n  const depth = calculateDepth(rule);\n  const conditionCount = countConditions(rule);\n  \n  if (depth > maxDepth) {\n    throw new Error(`Rule exceeds maximum depth of ${maxDepth}`);\n  }\n  \n  if (conditionCount > maxConditions) {\n    throw new Error(`Rule exceeds maximum conditions of ${maxConditions}`);\n  }\n}\n```\n\n### 3. Sanitize Regex Patterns\n\n```typescript\nfunction validateRegexPattern(pattern: string): void {\n  const dangerousPatterns = [\n    /\\(\\?<[!=]/,  // Lookbehind assertions\n    /\\(\\?\\(/,     // Conditional patterns\n    /\\{1000,\\}/   // Large repetitions\n  ];\n  \n  if (dangerousPatterns.some(p => p.test(pattern))) {\n    throw new Error('Potentially dangerous regex pattern');\n  }\n}\n```\n\n### 4. Use Allowlists for Dynamic Fields\n\n```typescript\nconst allowedFields = new Set([\n  'user.name',\n  'user.email',\n  'user.role',\n  'order.total'\n]);\n\nfunction validateFieldAccess(field: string): void {\n  const normalizedField = field.replace(/^\\$\\./, '');\n  if (!allowedFields.has(normalizedField)) {\n    throw new Error(`Access to field '${field}' is not allowed`);\n  }\n}\n```\n\n## Maintenance & Documentation\n\n### 1. Document Rule Purpose and Context\n\n```typescript\ninterface DocumentedRule extends RuleType {\n  metadata: {\n    id: string;\n    name: string;\n    description: string;\n    author: string;\n    created: Date;\n    modified: Date;\n    tags: string[];\n    examples: Array<{\n      input: any;\n      expectedOutput: any;\n    }>;\n  };\n}\n```\n\n### 2. Version Your Rules\n\n```typescript\ninterface VersionedRule extends RuleType {\n  version: string;\n  changelog: Array<{\n    version: string;\n    date: Date;\n    changes: string[];\n  }>;\n}\n```\n\n### 3. Create Rule Catalogs\n\n```typescript\nclass RuleCatalog {\n  private rules = new Map<string, DocumentedRule>();\n  \n  register(rule: DocumentedRule): void {\n    this.validateRule(rule);\n    this.rules.set(rule.metadata.id, rule);\n  }\n  \n  findByTags(tags: string[]): DocumentedRule[] {\n    return Array.from(this.rules.values())\n      .filter(rule => \n        tags.some(tag => rule.metadata.tags.includes(tag))\n      );\n  }\n  \n  generateDocumentation(): string {\n    // Generate markdown documentation\n    return Array.from(this.rules.values())\n      .map(rule => this.formatRuleDoc(rule))\n      .join('\\n\\n');\n  }\n}\n```\n\n## Common Pitfalls\n\n### 1. Incorrect JSONPath Usage\n\n**❌ Bad: Missing $**\n```typescript\n{ field: \"user.name\", operator: \"equals\", value: \"John\" }\n```\n\n**✅ Good: Proper JSONPath**\n```typescript\n{ field: \"$.user.name\", operator: \"equals\", value: \"John\" }\n// or\n{ field: \"user.name\", operator: \"equals\", value: \"John\" } // Simple path\n```\n\n### 2. Type Mismatches\n\n**❌ Bad: String vs Number**\n```typescript\n{ field: \"age\", operator: \"greater-than\", value: \"18\" } // String \"18\"\n```\n\n**✅ Good: Correct Types**\n```typescript\n{ field: \"age\", operator: \"greater-than\", value: 18 } // Number 18\n```\n\n### 3. Forgetting Default Values\n\n**❌ Bad: No Default**\n```typescript\n{\n  conditions: [\n    { and: [...], result: { status: \"approved\" } },\n    { and: [...], result: { status: \"pending\" } }\n  ]\n  // What if no conditions match?\n}\n```\n\n**✅ Good: Always Include Default**\n```typescript\n{\n  conditions: [\n    { and: [...], result: { status: \"approved\" } },\n    { and: [...], result: { status: \"pending\" } }\n  ],\n  default: { status: \"rejected\" }\n}\n```\n\n### 4. Overly Complex Conditions\n\n**❌ Bad: Deeply Nested**\n```typescript\n{\n  conditions: {\n    or: [{\n      and: [{\n        or: [{\n          and: [{\n            or: [/* ... */]\n          }]\n        }]\n      }]\n    }]\n  }\n}\n```\n\n**✅ Good: Flattened Logic**\n```typescript\n{\n  conditions: [\n    { and: [/* condition set 1 */], result: /* ... */ },\n    { and: [/* condition set 2 */], result: /* ... */ },\n    { and: [/* condition set 3 */], result: /* ... */ }\n  ]\n}\n```\n\n### 5. Not Handling Array Fields Properly\n\n**❌ Bad: Assuming Single Value**\n```typescript\n{ field: \"$.tags\", operator: \"equals\", value: \"important\" }\n```\n\n**✅ Good: Use Array Operators**\n```typescript\n{ field: \"$.tags\", operator: \"contains\", value: \"important\" }\n```\n\n## Summary Checklist\n\n- [ ] Keep rules simple and focused\n- [ ] Use meaningful field names\n- [ ] Order conditions for performance\n- [ ] Validate rules before production\n- [ ] Handle errors gracefully\n- [ ] Write comprehensive tests\n- [ ] Document rule purpose and usage\n- [ ] Consider security implications\n- [ ] Use appropriate operators\n- [ ] Include default values\n- [ ] Avoid overly complex nesting\n- [ ] Version and track rule changes\n\n---\n\nFor more information, see the [main documentation](../README.md)."
  },
  {
    "path": "packages/core/docs/index.md",
    "content": "# @usex/rule-engine Documentation\n\nWelcome to the comprehensive documentation for @usex/rule-engine - a simple yet powerful rule engine for Node.js and the browser.\n\n## 📚 Documentation Overview\n\n### Getting Started\n- [**README**](../README.md) - Installation, quick start, and features overview\n- [**API Reference**](./api-reference.md) - Complete API documentation\n- [**TypeScript Guide**](../README.md#typescript-support) - Type-safe usage examples\n\n### Core Concepts\n- [**Operators Guide**](./operators.md) - All 126 operators with examples\n- [**Best Practices**](./best-practices.md) - Production-ready patterns and tips\n- [**Examples**](../README.md#examples) - Real-world use cases\n\n### Migration & Integration\n- [**Migration Guide**](./migration-guide.md) - Migrate from other rule engines\n- [**Common Patterns**](./migration-guide.md#common-migration-patterns) - Convert existing logic\n\n## 🚀 Quick Links\n\n| Resource | Description |\n|----------|-------------|\n| [GitHub Repository](https://github.com/ali-master/rule-engine) | Source code and issues |\n| [npm Package](https://www.npmjs.com/package/@usex/rule-engine) | Latest releases |\n| [Changelog](https://github.com/ali-master/rule-engine/releases) | Version history |\n| [License](../../../LICENSE) | MIT License |\n\n## 📖 Documentation Structure\n\n```\ndocs/\n├── index.md              # This file - Documentation hub\n├── api-reference.md      # Complete API documentation\n├── operators.md          # All 126 operators reference\n├── best-practices.md     # Production best practices\n└── migration-guide.md    # Migration from other engines\n```\n\n## 🎯 Common Use Cases\n\n### 1. Business Rules\n- Discount calculations\n- Pricing strategies\n- Approval workflows\n- Access control\n\n### 2. Validation\n- Form validation\n- Data integrity\n- Input sanitization\n- Schema validation\n\n### 3. Personalization\n- Content filtering\n- Feature flags\n- User segmentation\n- Recommendation engines\n\n### 4. Automation\n- Workflow automation\n- Alert triggers\n- Event processing\n- Decision trees\n\n## 💡 Key Features at a Glance\n\n| Feature | Description |\n|---------|-------------|\n| **Zero Dependencies** | Lightweight core, optional peer dependencies |\n| **JSONPath Support** | Access nested properties with `$.path.to.field` |\n| **126+ Operators** | Comprehensive operator set for any use case |\n| **Type Safety** | Full TypeScript support with generics |\n| **Builder Pattern** | Fluent API for programmatic rule creation |\n| **Async Support** | Promise-based evaluation |\n| **Batch Processing** | Evaluate multiple criteria efficiently |\n| **Rule Introspection** | Analyze rules for possible inputs |\n| **Mutations** | Transform data before evaluation |\n| **Cross-platform** | Works in Node.js and browsers |\n\n## 📊 Quick Comparison\n\n### Operator Categories\n\n| Category | Count | Examples |\n|----------|-------|----------|\n| Comparison | 6 | `equals`, `greater-than`, `less-than` |\n| String | 12 | `like`, `starts-with`, `email`, `url` |\n| Numeric | 11 | `between`, `positive`, `even`, `integer` |\n| Array | 12 | `contains`, `contains-any`, `array-length` |\n| Date/Time | 14 | `date-after`, `date-between`, `time-equals` |\n| Type | 10 | `string`, `number`, `array`, `object` |\n| Existence | 6 | `exists`, `empty`, `null-or-undefined` |\n| Boolean | 4 | `truthy`, `falsy`, `boolean-string` |\n| Pattern | 2 | `matches`, `not-matches` |\n| Persian | 3 | `persian-alpha`, `persian-number` |\n\n## 🔧 Quick Setup\n\n```bash\n# Install\nnpm install @usex/rule-engine\n\n# Basic usage\nimport { RuleEngine } from '@usex/rule-engine';\n\nconst rule = {\n  conditions: {\n    and: [\n      { field: \"age\", operator: \"greater-than\", value: 18 },\n      { field: \"country\", operator: \"equals\", value: \"US\" }\n    ]\n  },\n  default: { allowed: false }\n};\n\nconst result = await RuleEngine.evaluate(rule, { \n  age: 25, \n  country: \"US\" \n});\n// { value: { allowed: true }, isPassed: true }\n```\n\n## 🛠️ Development\n\n```bash\n# Clone repository\ngit clone https://github.com/ali-master/rule-engine.git\n\n# Install dependencies\npnpm install\n\n# Run tests\npnpm test\n\n# Build\npnpm build\n```\n\n## 🤝 Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](../../../CONTRIBUTING.md) for details.\n\n## 📝 License\n\nMIT © [Ali Torki](https://github.com/ali-master)\n\n---\n\n<div align=\"center\">\n  <p>Made with ❤️ by <a href=\"https://github.com/ali-master\">Ali Torki</a></p>\n  <p>\n    <a href=\"https://github.com/ali-master/rule-engine\">GitHub</a> •\n    <a href=\"https://www.npmjs.com/package/@usex/rule-engine\">npm</a> •\n    <a href=\"https://github.com/ali-master/rule-engine/issues\">Issues</a>\n  </p>\n</div>"
  },
  {
    "path": "packages/core/docs/migration-guide.md",
    "content": "# Migration Guide\n\nThis guide helps you migrate from other rule engines to @usex/rule-engine.\n\n## Table of Contents\n\n- [From json-rules-engine](#from-json-rules-engine)\n- [From node-rules](#from-node-rules)\n- [From business-rules-engine](#from-business-rules-engine)\n- [From custom implementations](#from-custom-implementations)\n- [Common Migration Patterns](#common-migration-patterns)\n\n## From json-rules-engine\n\n### Rule Structure Comparison\n\n#### json-rules-engine\n```javascript\n{\n  conditions: {\n    all: [{\n      fact: 'age',\n      operator: 'greaterThanInclusive',\n      value: 18\n    }, {\n      fact: 'country',\n      operator: 'equal',\n      value: 'US'\n    }]\n  },\n  event: {\n    type: 'adult-us-citizen',\n    params: {\n      canVote: true\n    }\n  }\n}\n```\n\n#### @usex/rule-engine\n```javascript\n{\n  conditions: {\n    and: [{\n      field: 'age',\n      operator: 'greater-than-or-equals',\n      value: 18\n    }, {\n      field: 'country',\n      operator: 'equals',\n      value: 'US'\n    }],\n    result: {\n      canVote: true,\n      type: 'adult-us-citizen'\n    }\n  }\n}\n```\n\n### Key Differences\n\n| Feature | json-rules-engine | @usex/rule-engine |\n|---------|------------------|-------------------|\n| Field Reference | `fact` | `field` |\n| Logical Operators | `all`, `any` | `and`, `or`, `none` |\n| Results | `event` system | `result` in conditions or `default` |\n| Async Support | Facts can be promises | Built-in async evaluation |\n| JSONPath | Not supported | Full support with `$.path.to.field` |\n\n### Migration Example\n\n```javascript\n// json-rules-engine\n// @usex/rule-engine\nimport { RuleEngine } from '@usex/rule-engine';\n\nconst Engine = require('json-rules-engine');\nconst engine = new Engine();\n\nengine.addRule({\n  conditions: {\n    any: [{\n      all: [{\n        fact: 'account.balance',\n        operator: 'greaterThan',\n        value: 100\n      }]\n    }, {\n      fact: 'account.type',\n      operator: 'equal',\n      value: 'premium'\n    }]\n  },\n  event: {\n    type: 'offer-discount',\n    params: { discount: 0.25 }\n  }\n});\n\nconst facts = { account: { balance: 150, type: 'basic' } };\nconst { events } = await engine.run(facts);\n\nconst rule = {\n  conditions: {\n    or: [{\n      and: [{\n        field: '$.account.balance',\n        operator: 'greater-than',\n        value: 100\n      }]\n    }, {\n      field: '$.account.type',\n      operator: 'equals',\n      value: 'premium'\n    }],\n    result: {\n      discount: 0.25,\n      type: 'offer-discount'\n    }\n  }\n};\n\nconst result = await RuleEngine.evaluate(rule, facts);\n```\n\n## From node-rules\n\n### Rule Structure Comparison\n\n#### node-rules\n```javascript\n{\n  name: \"transaction-rule\",\n  priority: 1,\n  condition: function(R) {\n    R.when(this.amount > 500 && this.cardType === 'Credit');\n  },\n  consequence: function(R) {\n    this.result = {\n      requiresApproval: true,\n      reason: 'High value credit transaction'\n    };\n    R.stop();\n  }\n}\n```\n\n#### @usex/rule-engine\n```javascript\n{\n  conditions: {\n    and: [{\n      field: 'amount',\n      operator: 'greater-than',\n      value: 500\n    }, {\n      field: 'cardType',\n      operator: 'equals',\n      value: 'Credit'\n    }],\n    result: {\n      requiresApproval: true,\n      reason: 'High value credit transaction'\n    }\n  }\n}\n```\n\n### Key Differences\n\n| Feature | node-rules | @usex/rule-engine |\n|---------|-----------|-------------------|\n| Rule Definition | JavaScript functions | JSON structure |\n| Priority System | Built-in priority | Order-based evaluation |\n| Flow Control | `R.stop()`, `R.next()` | Automatic based on conditions |\n| Rule Chaining | Sequential with flow control | Declarative with logical operators |\n\n### Migration Example\n\n```javascript\n// node-rules\nconst RuleEngine = require('node-rules');\n\nconst rules = [{\n  name: \"premium-discount\",\n  condition: function(R) {\n    R.when(this.customer.tier === 'premium' && this.orderTotal > 100);\n  },\n  consequence: function(R) {\n    this.discount = 0.20;\n    this.message = 'Premium customer discount';\n    R.stop();\n  }\n}, {\n  name: \"bulk-discount\",\n  condition: function(R) {\n    R.when(this.orderTotal > 500);\n  },\n  consequence: function(R) {\n    this.discount = 0.15;\n    this.message = 'Bulk order discount';\n    R.stop();\n  }\n}];\n\nconst R = new RuleEngine(rules);\nconst fact = {\n  customer: { tier: 'premium' },\n  orderTotal: 150\n};\n\nR.execute(fact, function(result) {\n  console.log(result.discount); // 0.20\n});\n\n// @usex/rule-engine\nimport { RuleEngine } from '@usex/rule-engine';\n\nconst rule = {\n  conditions: [{\n    and: [{\n      field: '$.customer.tier',\n      operator: 'equals',\n      value: 'premium'\n    }, {\n      field: 'orderTotal',\n      operator: 'greater-than',\n      value: 100\n    }],\n    result: {\n      discount: 0.20,\n      message: 'Premium customer discount'\n    }\n  }, {\n    and: [{\n      field: 'orderTotal',\n      operator: 'greater-than',\n      value: 500\n    }],\n    result: {\n      discount: 0.15,\n      message: 'Bulk order discount'\n    }\n  }],\n  default: {\n    discount: 0,\n    message: 'No discount applicable'\n  }\n};\n\nconst result = await RuleEngine.evaluate(rule, fact);\nconsole.log(result.value.discount); // 0.20\n```\n\n## From business-rules-engine\n\n### Rule Structure Comparison\n\n#### business-rules-engine\n```javascript\n{\n  name: \"age-validation\",\n  rules: [\n    {\n      field: \"age\",\n      method: \"greaterThan\",\n      value: 18,\n      message: \"Must be over 18\"\n    },\n    {\n      field: \"age\",\n      method: \"lessThan\",\n      value: 100,\n      message: \"Invalid age\"\n    }\n  ]\n}\n```\n\n#### @usex/rule-engine\n```javascript\n{\n  conditions: {\n    and: [{\n      field: 'age',\n      operator: 'greater-than',\n      value: 18,\n      message: 'Must be over 18'\n    }, {\n      field: 'age',\n      operator: 'less-than',\n      value: 100,\n      message: 'Invalid age'\n    }]\n  }\n}\n```\n\n### Key Differences\n\n| Feature | business-rules-engine | @usex/rule-engine |\n|---------|---------------------|-------------------|\n| Validation Focus | Built for validation | General purpose with validation support |\n| Error Messages | Built-in message handling | Optional message field |\n| Rule Grouping | Array of rules | Logical operators |\n| Custom Validators | Method-based | Operator-based |\n\n### Migration Example\n\n```javascript\n// business-rules-engine\nconst BusinessRulesEngine = require('business-rules-engine');\n\nconst rule = new BusinessRulesEngine.Rule();\nrule.name = \"user-registration\";\n\nrule.addRule({\n  field: \"email\",\n  method: \"email\",\n  message: \"Invalid email\"\n});\n\nrule.addRule({\n  field: \"password\",\n  method: \"minLength\",\n  value: 8,\n  message: \"Password too short\"\n});\n\nconst result = rule.validate({\n  email: \"user@example.com\",\n  password: \"short\"\n});\n\n// @usex/rule-engine\nimport { RuleEngine } from '@usex/rule-engine';\n\nconst rule = {\n  conditions: {\n    and: [{\n      field: 'email',\n      operator: 'email',\n      value: true,\n      message: 'Invalid email'\n    }, {\n      field: 'password',\n      operator: 'min-length',\n      value: 8,\n      message: 'Password too short'\n    }]\n  }\n};\n\nconst result = await RuleEngine.evaluate(rule, {\n  email: \"user@example.com\",\n  password: \"short\"\n});\n\n// Extract validation errors\nif (!result.isPassed) {\n  const errors = rule.conditions.and\n    .filter(c => !evaluateConstraint(c, data))\n    .map(c => c.message);\n}\n```\n\n## From custom implementations\n\n### Common Patterns\n\n#### If-Else Chains\n```javascript\n// Before\nfunction calculateDiscount(customer, order) {\n  if (customer.tier === 'platinum' && order.total > 1000) {\n    return 0.25;\n  } else if (customer.tier === 'gold' && order.total > 500) {\n    return 0.20;\n  } else if (order.total > 1000) {\n    return 0.15;\n  } else if (customer.isNewCustomer && order.total > 100) {\n    return 0.10;\n  } else {\n    return 0;\n  }\n}\n\n// After\nconst discountRule = {\n  conditions: [{\n    and: [\n      { field: '$.customer.tier', operator: 'equals', value: 'platinum' },\n      { field: '$.order.total', operator: 'greater-than', value: 1000 }\n    ],\n    result: 0.25\n  }, {\n    and: [\n      { field: '$.customer.tier', operator: 'equals', value: 'gold' },\n      { field: '$.order.total', operator: 'greater-than', value: 500 }\n    ],\n    result: 0.20\n  }, {\n    and: [\n      { field: '$.order.total', operator: 'greater-than', value: 1000 }\n    ],\n    result: 0.15\n  }, {\n    and: [\n      { field: '$.customer.isNewCustomer', operator: 'equals', value: true },\n      { field: '$.order.total', operator: 'greater-than', value: 100 }\n    ],\n    result: 0.10\n  }],\n  default: 0\n};\n\nconst discount = await RuleEngine.getEvaluateResult(discountRule, { customer, order });\n```\n\n#### Switch Statements\n```javascript\n// Before\nfunction getAccessLevel(user) {\n  switch(user.role) {\n    case 'admin':\n      return { read: true, write: true, delete: true };\n    case 'editor':\n      return { read: true, write: true, delete: false };\n    case 'viewer':\n      return { read: true, write: false, delete: false };\n    default:\n      return { read: false, write: false, delete: false };\n  }\n}\n\n// After\nconst accessRule = {\n  conditions: [{\n    and: [{ field: 'role', operator: 'equals', value: 'admin' }],\n    result: { read: true, write: true, delete: true }\n  }, {\n    and: [{ field: 'role', operator: 'equals', value: 'editor' }],\n    result: { read: true, write: true, delete: false }\n  }, {\n    and: [{ field: 'role', operator: 'equals', value: 'viewer' }],\n    result: { read: true, write: false, delete: false }\n  }],\n  default: { read: false, write: false, delete: false }\n};\n\nconst access = await RuleEngine.getEvaluateResult(accessRule, user);\n```\n\n## Common Migration Patterns\n\n### 1. Dynamic Field References\n\nMany rule engines don't support referencing other fields in values:\n\n```javascript\n// Using JSONPath to reference other fields\n{\n  conditions: {\n    and: [{\n      field: '$.current.price',\n      operator: 'less-than',\n      value: '$.maximum.price' // Reference another field\n    }]\n  }\n}\n```\n\n### 2. Complex Nested Conditions\n\nConvert complex boolean logic to nested conditions:\n\n```javascript\n// (A && B) || (C && D) || E\n{\n  conditions: {\n    or: [{\n      and: [conditionA, conditionB]\n    }, {\n      and: [conditionC, conditionD]\n    },\n    conditionE\n    ]\n  }\n}\n```\n\n### 3. Array Operations\n\nLeverage built-in array operators:\n\n```javascript\n{\n  conditions: {\n    and: [{\n      field: 'tags',\n      operator: 'contains-any',\n      value: ['urgent', 'critical', 'high-priority']\n    }, {\n      field: 'assignees',\n      operator: 'not-empty',\n      value: true\n    }]\n  }\n}\n```\n\n### 4. Date Comparisons\n\nUse specialized date operators:\n\n```javascript\n{\n  conditions: {\n    and: [{\n      field: 'subscription.expiresAt',\n      operator: 'date-after-now',\n      value: true\n    }, {\n      field: 'lastPayment',\n      operator: 'date-between',\n      value: ['2025-01-01', '2025-12-31']\n    }]\n  }\n}\n```\n\n### 5. Validation Rules\n\nConvert validation logic to rules with messages:\n\n```javascript\n{\n  conditions: {\n    and: [{\n      field: 'username',\n      operator: 'matches',\n      value: '^[a-zA-Z0-9_]{3,20}$',\n      message: 'Username must be 3-20 characters, alphanumeric and underscore only'\n    }, {\n      field: 'email',\n      operator: 'email',\n      value: true,\n      message: 'Please enter a valid email address'\n    }]\n  }\n}\n```\n\n## Best Practices for Migration\n\n1. **Start Simple**: Migrate basic rules first, then tackle complex ones\n2. **Test Thoroughly**: Create comprehensive test suites during migration\n3. **Use TypeScript**: Leverage type safety for rule definitions\n4. **Validate Rules**: Use the validation API to catch errors early\n5. **Document Rules**: Add comments and maintain rule documentation\n6. **Performance Test**: Compare performance with your previous solution\n7. **Incremental Migration**: Run old and new systems in parallel initially\n\n## Need Help?\n\nIf you encounter issues during migration:\n\n1. Check the [API Reference](./api-reference.md)\n2. Review the [Operators Guide](./operators.md)\n3. See [Examples](../README.md#examples) for common patterns\n4. Open an issue on [GitHub](https://github.com/ali-master/rule-engine/issues)\n\n---\n\nFor more information, see the [main documentation](../README.md).\n"
  },
  {
    "path": "packages/core/docs/operators.md",
    "content": "# Complete Operator Reference\n\nThis document provides a comprehensive reference for all 126 operators available in @usex/rule-engine.\n\n## Table of Contents\n\n- [Comparison Operators](#comparison-operators)\n- [String Operators](#string-operators)\n- [Numeric Operators](#numeric-operators)\n- [Array Operators](#array-operators)\n- [Date & Time Operators](#date--time-operators)\n- [Type Validation Operators](#type-validation-operators)\n- [Existence Operators](#existence-operators)\n- [Length & Range Operators](#length--range-operators)\n- [Boolean Operators](#boolean-operators)\n- [Pattern Matching Operators](#pattern-matching-operators)\n- [Persian Text Operators](#persian-text-operators)\n\n## Comparison Operators\n\n### Basic Comparison\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `equals` | Exact equality check | `{ field: \"status\", operator: \"equals\", value: \"active\" }` | Strict equality (===) |\n| `not-equals` | Not equal check | `{ field: \"role\", operator: \"not-equals\", value: \"guest\" }` | Strict inequality (!==) |\n| `greater-than` | Greater than comparison | `{ field: \"age\", operator: \"greater-than\", value: 18 }` | Works with numbers, strings, dates |\n| `less-than` | Less than comparison | `{ field: \"price\", operator: \"less-than\", value: 100 }` | Works with numbers, strings, dates |\n| `greater-than-or-equals` | Greater than or equal | `{ field: \"score\", operator: \"greater-than-or-equals\", value: 80 }` | Inclusive comparison |\n| `less-than-or-equals` | Less than or equal | `{ field: \"quantity\", operator: \"less-than-or-equals\", value: 10 }` | Inclusive comparison |\n\n## String Operators\n\n### String Comparison\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `like` | Case-insensitive contains | `{ field: \"name\", operator: \"like\", value: \"john\" }` | Substring match |\n| `not-like` | Case-insensitive not contains | `{ field: \"email\", operator: \"not-like\", value: \"spam\" }` | Substring exclusion |\n| `starts-with` | String starts with | `{ field: \"url\", operator: \"starts-with\", value: \"https://\" }` | Case-sensitive |\n| `not-starts-with` | String doesn't start with | `{ field: \"path\", operator: \"not-starts-with\", value: \"/admin\" }` | Case-sensitive |\n| `ends-with` | String ends with | `{ field: \"filename\", operator: \"ends-with\", value: \".pdf\" }` | Case-sensitive |\n| `not-ends-with` | String doesn't end with | `{ field: \"email\", operator: \"not-ends-with\", value: \".temp\" }` | Case-sensitive |\n\n### String Validation\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `email` | Valid email format | `{ field: \"contact\", operator: \"email\", value: true }` | RFC 5322 compliant |\n| `url` | Valid URL format | `{ field: \"website\", operator: \"url\", value: true }` | Includes protocol |\n| `uuid` | Valid UUID format | `{ field: \"id\", operator: \"uuid\", value: true }` | v1-v5 UUIDs |\n| `alpha` | Only alphabetic characters | `{ field: \"firstName\", operator: \"alpha\", value: true }` | A-Z, a-z only |\n| `alpha-numeric` | Alphanumeric characters | `{ field: \"username\", operator: \"alpha-numeric\", value: true }` | A-Z, a-z, 0-9 |\n| `numeric` | Only numeric characters | `{ field: \"zipCode\", operator: \"numeric\", value: true }` | 0-9 only |\n| `lower-case` | All lowercase | `{ field: \"code\", operator: \"lower-case\", value: true }` | No uppercase letters |\n| `upper-case` | All uppercase | `{ field: \"countryCode\", operator: \"upper-case\", value: true }` | No lowercase letters |\n\n## Numeric Operators\n\n### Number Validation\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `integer` | Is integer number | `{ field: \"count\", operator: \"integer\", value: true }` | No decimals |\n| `float` | Is floating point | `{ field: \"price\", operator: \"float\", value: true }` | Has decimals |\n| `positive` | Positive number | `{ field: \"balance\", operator: \"positive\", value: true }` | > 0 |\n| `negative` | Negative number | `{ field: \"debt\", operator: \"negative\", value: true }` | < 0 |\n| `zero` | Equals zero | `{ field: \"remaining\", operator: \"zero\", value: true }` | === 0 |\n| `even` | Even number | `{ field: \"pageNumber\", operator: \"even\", value: true }` | n % 2 === 0 |\n| `odd` | Odd number | `{ field: \"id\", operator: \"odd\", value: true }` | n % 2 !== 0 |\n\n### Range Operators\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `between` | Number in range | `{ field: \"age\", operator: \"between\", value: [18, 65] }` | Inclusive |\n| `number-between` | Alias for between | `{ field: \"score\", operator: \"number-between\", value: [0, 100] }` | Inclusive |\n| `min` | Minimum value | `{ field: \"age\", operator: \"min\", value: 18 }` | >= value |\n| `max` | Maximum value | `{ field: \"amount\", operator: \"max\", value: 1000 }` | <= value |\n\n## Array Operators\n\n### Array Operations\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `in` | Value in array | `{ field: \"role\", operator: \"in\", value: [\"admin\", \"moderator\"] }` | Exact match |\n| `not-in` | Value not in array | `{ field: \"status\", operator: \"not-in\", value: [\"banned\", \"suspended\"] }` | Exclusion |\n| `contains` | Array contains value | `{ field: \"tags\", operator: \"contains\", value: \"featured\" }` | Single value |\n| `not-contains` | Array doesn't contain | `{ field: \"permissions\", operator: \"not-contains\", value: \"delete\" }` | Single value |\n| `contains-any` | Contains any of values | `{ field: \"skills\", operator: \"contains-any\", value: [\"js\", \"ts\", \"python\"] }` | OR logic |\n| `contains-all` | Contains all values | `{ field: \"requirements\", operator: \"contains-all\", value: [\"degree\", \"experience\"] }` | AND logic |\n| `not-contains-any` | Doesn't contain any | `{ field: \"allergies\", operator: \"not-contains-any\", value: [\"nuts\", \"dairy\"] }` | None match |\n| `not-contains-all` | Doesn't contain all | `{ field: \"features\", operator: \"not-contains-all\", value: [\"premium\", \"pro\"] }` | Not all match |\n\n### Array Properties\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `array-length` | Array length equals | `{ field: \"items\", operator: \"array-length\", value: 5 }` | Exact count |\n| `array-min-length` | Minimum array length | `{ field: \"tags\", operator: \"array-min-length\", value: 1 }` | >= count |\n| `array-max-length` | Maximum array length | `{ field: \"selections\", operator: \"array-max-length\", value: 10 }` | <= count |\n| `array-length-between` | Array length in range | `{ field: \"choices\", operator: \"array-length-between\", value: [2, 5] }` | Inclusive |\n\n## Date & Time Operators\n\n### Date Comparison\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `date-after` | Date is after | `{ field: \"expiry\", operator: \"date-after\", value: \"2025-01-01\" }` | Supports ISO 8601 |\n| `date-before` | Date is before | `{ field: \"created\", operator: \"date-before\", value: \"2023-12-31\" }` | Supports ISO 8601 |\n| `date-equals` | Date equals | `{ field: \"birthday\", operator: \"date-equals\", value: \"1990-05-15\" }` | Day precision |\n| `date-not-equals` | Date not equals | `{ field: \"lastLogin\", operator: \"date-not-equals\", value: \"2025-01-01\" }` | Day precision |\n| `date-between` | Date in range | `{ field: \"event\", operator: \"date-between\", value: [\"2025-01-01\", \"2025-12-31\"] }` | Inclusive |\n\n### Relative Date Operators\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `date-after-now` | Date after current date | `{ field: \"expires\", operator: \"date-after-now\", value: true }` | Future dates |\n| `date-before-now` | Date before current date | `{ field: \"created\", operator: \"date-before-now\", value: true }` | Past dates |\n| `date-equals-now` | Date equals today | `{ field: \"scheduled\", operator: \"date-equals-now\", value: true }` | Today's date |\n| `date-not-equals-now` | Date not today | `{ field: \"appointment\", operator: \"date-not-equals-now\", value: true }` | Not today |\n\n### Time Operators\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `time-after` | Time is after | `{ field: \"startTime\", operator: \"time-after\", value: \"09:00\" }` | HH:mm format |\n| `time-before` | Time is before | `{ field: \"endTime\", operator: \"time-before\", value: \"17:00\" }` | HH:mm format |\n| `time-equals` | Time equals | `{ field: \"alarm\", operator: \"time-equals\", value: \"08:30\" }` | Exact match |\n| `time-not-equals` | Time not equals | `{ field: \"meeting\", operator: \"time-not-equals\", value: \"12:00\" }` | Not exact |\n| `time-between` | Time in range | `{ field: \"workHours\", operator: \"time-between\", value: [\"09:00\", \"17:00\"] }` | Inclusive |\n\n## Type Validation Operators\n\n### Data Type Checks\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `string` | Is string type | `{ field: \"name\", operator: \"string\", value: true }` | typeof === 'string' |\n| `number` | Is number type | `{ field: \"age\", operator: \"number\", value: true }` | typeof === 'number' |\n| `boolean` | Is boolean type | `{ field: \"active\", operator: \"boolean\", value: true }` | typeof === 'boolean' |\n| `object` | Is object type | `{ field: \"metadata\", operator: \"object\", value: true }` | Non-null object |\n| `array` | Is array type | `{ field: \"items\", operator: \"array\", value: true }` | Array.isArray() |\n| `date` | Is date type | `{ field: \"created\", operator: \"date\", value: true }` | Valid Date object |\n| `function` | Is function type | `{ field: \"callback\", operator: \"function\", value: true }` | typeof === 'function' |\n| `null` | Is null | `{ field: \"deleted\", operator: \"null\", value: true }` | === null |\n| `undefined` | Is undefined | `{ field: \"optional\", operator: \"undefined\", value: true }` | === undefined |\n\n## Existence Operators\n\n### Field Existence\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `exists` | Field exists | `{ field: \"email\", operator: \"exists\", value: true }` | Property defined |\n| `not-exists` | Field doesn't exist | `{ field: \"tempData\", operator: \"not-exists\", value: true }` | Property undefined |\n| `null-or-undefined` | Null or undefined | `{ field: \"optional\", operator: \"null-or-undefined\", value: true }` | == null |\n| `not-null-or-undefined` | Not null/undefined | `{ field: \"required\", operator: \"not-null-or-undefined\", value: true }` | != null |\n\n### Emptiness Checks\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `empty` | Is empty | `{ field: \"notes\", operator: \"empty\", value: true }` | \"\", [], {}, null, undefined |\n| `not-empty` | Is not empty | `{ field: \"description\", operator: \"not-empty\", value: true }` | Has content |\n| `null-or-white-space` | Null or whitespace | `{ field: \"comment\", operator: \"null-or-white-space\", value: true }` | No meaningful text |\n| `not-null-or-white-space` | Has content | `{ field: \"title\", operator: \"not-null-or-white-space\", value: true }` | Non-empty text |\n\n## Length & Range Operators\n\n### String Length\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `string-length` | Exact length | `{ field: \"code\", operator: \"string-length\", value: 6 }` | === length |\n| `min-length` | Minimum length | `{ field: \"password\", operator: \"min-length\", value: 8 }` | >= length |\n| `max-length` | Maximum length | `{ field: \"username\", operator: \"max-length\", value: 20 }` | <= length |\n| `length-between` | Length in range | `{ field: \"bio\", operator: \"length-between\", value: [10, 500] }` | Inclusive |\n\n## Boolean Operators\n\n### Boolean Logic\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `truthy` | Truthy value | `{ field: \"enabled\", operator: \"truthy\", value: true }` | !!value === true |\n| `falsy` | Falsy value | `{ field: \"disabled\", operator: \"falsy\", value: true }` | !value === true |\n| `boolean-string` | String boolean | `{ field: \"flag\", operator: \"boolean-string\", value: true }` | \"true\" or \"false\" |\n| `boolean-number` | Numeric boolean | `{ field: \"active\", operator: \"boolean-number\", value: true }` | 0 or 1 |\n\n## Pattern Matching Operators\n\n### Regular Expressions\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `matches` | Regex match | `{ field: \"phone\", operator: \"matches\", value: \"^\\\\d{3}-\\\\d{3}-\\\\d{4}$\" }` | Full regex support |\n| `not-matches` | Regex not match | `{ field: \"text\", operator: \"not-matches\", value: \"\\\\b(spam|junk)\\\\b\" }` | Exclusion pattern |\n\n## Persian Text Operators\n\n### Persian Validation\n\n| Operator | Description | Example | Notes |\n|----------|-------------|---------|-------|\n| `persian-alpha` | Persian letters only | `{ field: \"firstName\", operator: \"persian-alpha\", value: true }` | ا-ی only |\n| `persian-alpha-numeric` | Persian alphanumeric | `{ field: \"address\", operator: \"persian-alpha-numeric\", value: true }` | ا-ی and ۰-۹ |\n| `persian-number` | Persian numbers | `{ field: \"nationalId\", operator: \"persian-number\", value: true }` | ۰-۹ only |\n\n## Usage Examples\n\n### Complex Rule Example\n\n```typescript\nconst complexRule = {\n  conditions: {\n    and: [\n      // User validation\n      { field: \"email\", operator: \"email\", value: true },\n      { field: \"age\", operator: \"between\", value: [18, 100] },\n      { field: \"status\", operator: \"equals\", value: \"active\" },\n\n      // Profile requirements\n      { field: \"profile.bio\", operator: \"length-between\", value: [50, 500] },\n      { field: \"profile.skills\", operator: \"contains-any\", value: [\"javascript\", \"typescript\"] },\n      { field: \"profile.experience\", operator: \"greater-than\", value: 2 },\n\n      // Date validations\n      { field: \"joinDate\", operator: \"date-before-now\", value: true },\n      { field: \"subscription.expires\", operator: \"date-after-now\", value: true },\n\n      // Complex nested validation\n      {\n        or: [\n          { field: \"role\", operator: \"equals\", value: \"premium\" },\n          { field: \"credits\", operator: \"greater-than\", value: 100 }\n        ]\n      }\n    ]\n  }\n};\n```\n\n### Validation Rule Example\n\n```typescript\nconst formValidation = {\n  conditions: {\n    and: [\n      // Required fields\n      { field: \"username\", operator: \"not-null-or-undefined\", value: true, message: \"Username is required\" },\n      { field: \"username\", operator: \"alpha-numeric\", value: true, message: \"Username must be alphanumeric\" },\n      { field: \"username\", operator: \"length-between\", value: [3, 20], message: \"Username must be 3-20 characters\" },\n\n      // Email validation\n      { field: \"email\", operator: \"email\", value: true, message: \"Invalid email format\" },\n\n      // Password strength\n      { field: \"password\", operator: \"min-length\", value: 8, message: \"Password too short\" },\n      { field: \"password\", operator: \"matches\", value: \"^(?=.*[a-z])(?=.*[A-Z])(?=.*\\\\d)\", message: \"Password must contain uppercase, lowercase, and number\" },\n\n      // Confirmation\n      { field: \"confirmPassword\", operator: \"equals\", value: \"$.password\", message: \"Passwords don't match\" }\n    ]\n  }\n};\n```\n\n## Best Practices\n\n1. **Choose the Right Operator**: Use the most specific operator for your use case\n2. **Provide Messages**: Include helpful error messages for validation rules\n3. **Use JSONPath**: Leverage JSONPath for complex nested structures\n4. **Combine Operators**: Use logical grouping (and/or/none) for complex rules\n5. **Type Safety**: Validate data types before applying other operators\n6. **Performance**: Order conditions from most to least likely to fail for better performance\n\n---\n\nFor more information, see the [main documentation](../README.md).\n"
  },
  {
    "path": "packages/core/docs/refactoring-summary.md",
    "content": "# Rule Engine v2.1 Refactoring Summary\n\nThis document summarizes all the changes made during the TypeScript improvements and refactoring work.\n\n## Overview\n\nThe refactoring focused on enhancing TypeScript support through method overloads, improving type inference, and fixing various bugs discovered during the process.\n\n## Key Changes\n\n### 1. Method Overloads for Type Inference\n\nAdded TypeScript method overloads to automatically infer return types based on input:\n\n#### Evaluator Class (`evaluator.ts`)\n- `evaluate()` - Returns `EvaluationResult<T>` for single object, `Array<EvaluationResult<T>>` for arrays\n\n#### RuleEngine Class (`rule-engine.ts`)\n**Instance Methods:**\n- `evaluate()` - Async evaluation with type inference\n- `checkIsPassed()` - Returns `boolean` for single, `boolean | boolean[]` for arrays\n- `getEvaluateResult()` - Returns `T` for single, `T[]` for arrays\n- `evaluateMany()` (formerly `evaluateMultiple`) - Handles both single and array criteria\n\n**Static Methods:**\n- All instance methods also available as static methods with matching overloads\n\n#### ObjectDiscovery Class (`object-discovery.ts`)\n- `resolveProperty()` - Works with both objects and arrays\n- `updateProperty()` - Works with both objects and arrays\n- `resolveTextPathExpressions()` - Template string resolution for both types\n\n### 2. Singleton Pattern Enforcement\n\n**Change:** Made RuleEngine constructor private\n```typescript\n// Before\nconst engine = new RuleEngine();\n\n// After\nconst engine = RuleEngine.getInstance();\n```\n\n**Impact:** \n- Better resource management\n- Prevents multiple instances\n- Required updating all test files\n\n### 3. Bug Fixes\n\n#### Message Priority Fix\n**Issue:** Default rule messages were incorrectly prioritized over constraint-specific messages\n\n**Fix in `evaluator.ts`:**\n```typescript\n// Before (incorrect)\ndefaultResult?.message || lastErrorMessage\n\n// After (correct)\nlastErrorMessage || defaultResult?.message\n```\n\n#### Test Data Fix\n**Issue:** Test was using wrong field name\n```typescript\n// Before\n{ tenantId: \"1\", name: \"John\" }\n\n// After  \n{ levelId: 1, name: \"John\" }\n```\n\n#### Mutation Management\n**Issue:** `clearMutations()` only cleared cache, not mutations\n\n**Fix:**\n- Added `removeAll()` method to Mutator class\n- Updated `clearMutations()` to call `removeAll()`\n- Moved test cleanup from `beforeEach` to `afterEach` for proper isolation\n\n### 4. Documentation Updates\n\nCreated/Updated the following documentation:\n\n1. **`typescript-guide.md`** - Comprehensive guide for TypeScript features\n   - Method overload examples\n   - Singleton pattern usage\n   - Type-safe patterns\n   - Troubleshooting section\n\n2. **`api-reference-v2.md`** - Complete API reference\n   - All method signatures with overloads\n   - Configuration options\n   - Usage examples\n\n3. **`v2-migration-guide.md`** - Updated with v2.1 changes\n   - TypeScript improvements section\n   - Breaking changes (singleton pattern)\n   - Migration steps\n\n4. **`CHANGELOG.md`** - Detailed changelog\n   - All v2.1 improvements\n   - Technical details\n   - Before/after examples\n\n5. **`README.md`** - Updated main documentation\n   - Added links to new guides\n   - Updated feature list\n   - Added documentation section\n\n## Code Statistics\n\n### Files Modified\n- **Core Services:** 5 files\n  - `evaluator.ts`\n  - `rule-engine.ts` \n  - `object-discovery.ts`\n  - `mutator.ts`\n  - `introspector.ts`\n\n- **Test Files:** 2 files\n  - `engine.spec.ts`\n  - `mutator.spec.ts`\n\n- **Documentation:** 5 files\n  - `typescript-guide.md`\n  - `api-reference-v2.md`\n  - `v2-migration-guide.md`\n  - `CHANGELOG.md`\n  - `README.md`\n\n### Lines Changed\n- Approximately 500+ lines of code changes\n- 1000+ lines of documentation added\n\n## Benefits\n\n1. **Better Developer Experience**\n   - TypeScript automatically infers return types\n   - No need for type guards in most cases\n   - Clear compile-time errors\n\n2. **Improved Type Safety**\n   - Overloads prevent type confusion\n   - Singleton pattern prevents resource issues\n   - Better error messages\n\n3. **Bug Fixes**\n   - Correct error message priority\n   - Proper mutation cleanup\n   - Fixed test data issues\n\n4. **Comprehensive Documentation**\n   - Clear migration path\n   - TypeScript best practices\n   - Complete API reference\n\n## Testing\n\nAll 546 tests pass successfully:\n- 9 test files\n- No TypeScript errors (in vitest)\n- Performance tests show no regression\n\n## Next Steps\n\nThe refactoring is complete. Users can now:\n\n1. Use the new overloaded methods for better type inference\n2. Follow the migration guide to update their code\n3. Reference the TypeScript guide for best practices\n4. Use the API reference for detailed method signatures\n\n## Breaking Changes\n\n1. **Singleton Pattern**: Must use `RuleEngine.getInstance()` instead of `new RuleEngine()`\n2. **Method Rename**: `evaluateMultiple` → `evaluateMany` (for consistency)\n\nAll other changes are backward compatible."
  },
  {
    "path": "packages/core/docs/typescript-guide.md",
    "content": "# TypeScript Guide for @usex/rule-engine\n\nThis guide covers the enhanced TypeScript features in @usex/rule-engine v2.1, including improved type inference, method overloads, and best practices for type-safe rule evaluation.\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Type Inference with Method Overloads](#type-inference-with-method-overloads)\n- [Singleton Pattern and Instance Management](#singleton-pattern-and-instance-management)\n- [Working with Criteria Types](#working-with-criteria-types)\n- [Type-Safe Rule Building](#type-safe-rule-building)\n- [Custom Operators with Type Safety](#custom-operators-with-type-safety)\n- [Common TypeScript Patterns](#common-typescript-patterns)\n- [Troubleshooting](#troubleshooting)\n\n## Overview\n\nThe rule engine now provides enhanced TypeScript support through:\n\n1. **Method Overloads**: Automatic type inference based on input types\n2. **Improved Type Safety**: Better compile-time error detection\n3. **Generic Support**: Full support for custom result types\n4. **Singleton Pattern**: Proper type-safe instance management\n\n## Type Inference with Method Overloads\n\n### Evaluate Method\n\nThe `evaluate` method now has overloads that automatically infer the return type based on your input:\n\n```typescript\nimport { RuleEngine } from '@usex/rule-engine';\n\nconst engine = RuleEngine.getInstance();\nconst rule = {\n  conditions: {\n    and: [\n      { field: \"age\", operator: \"greater-than\", value: 18 }\n    ]\n  }\n};\n\n// Single object input - TypeScript knows result is EvaluationResult<T>\nconst singleResult = await engine.evaluate(rule, { age: 25 });\nconsole.log(singleResult.isPassed); // ✅ TypeScript knows this property exists\n\n// Array input - TypeScript knows result is Array<EvaluationResult<T>>\nconst arrayResults = await engine.evaluate(rule, [\n  { age: 25 },\n  { age: 16 }\n]);\nconsole.log(arrayResults[0].isPassed); // ✅ TypeScript knows this is an array\n```\n\n### Other Methods with Overloads\n\nSimilar overloads are available for:\n\n```typescript\n// checkIsPassed - returns boolean or boolean[]\nconst isPassed = await engine.checkIsPassed(rule, { age: 25 }); // boolean\nconst areAllPassed = await engine.checkIsPassed(rule, [{ age: 25 }, { age: 16 }]); // boolean | boolean[]\n\n// getEvaluateResult - returns T or T[]\nconst value = await engine.getEvaluateResult<number>(rule, { age: 25 }); // number\nconst values = await engine.getEvaluateResult<number>(rule, [{ age: 25 }]); // number[]\n\n// evaluateMany - evaluates multiple rules\nconst results = await engine.evaluateMany([rule1, rule2], { age: 25 }); // Array<EvaluationResult<T>>\n```\n\n## Singleton Pattern and Instance Management\n\nThe RuleEngine uses a singleton pattern for better resource management:\n\n```typescript\n// Always use getInstance() - constructor is private\nconst engine = RuleEngine.getInstance({\n  autoInitializeOperators: true,\n  enableCaching: true,\n  maxCacheSize: 100\n});\n\n// Static methods are also available\nconst result = await RuleEngine.evaluate(rule, criteria);\n\n// In tests, clean up between test cases\nbeforeEach(() => {\n  const engine = RuleEngine.getInstance();\n  engine.clearMutations();\n  engine.clearCache();\n});\n\n// Or use afterEach for cleanup\nafterEach(() => {\n  const engine = RuleEngine.getInstance();\n  engine.clearMutations();\n  engine.clearMutationCache();\n  engine.clearCache();\n});\n```\n\n## Working with Criteria Types\n\nThe library provides two main criteria types:\n\n```typescript\nimport type { Criteria, CriteriaObject } from '@usex/rule-engine';\n\n// CriteriaObject<T> - A single object\ntype UserCriteria = CriteriaObject<{\n  name: string;\n  age: number;\n}>;\n\n// Criteria<T> - Union type that can be object or array\ntype FlexibleCriteria = Criteria<UserData>;\n\n// The overloads handle both automatically\nasync function evaluateUser(userData: UserCriteria | UserData[]) {\n  const result = await engine.evaluate(rule, userData);\n  // TypeScript infers the correct return type\n}\n```\n\n## Type-Safe Rule Building\n\nUse TypeScript generics for type-safe rule results:\n\n```typescript\ninterface AccessRule {\n  level: 'admin' | 'user' | 'guest';\n  permissions: string[];\n}\n\nconst accessRule = {\n  conditions: [\n    {\n      and: [\n        { field: \"role\", operator: \"equals\", value: \"admin\" },\n        { field: \"active\", operator: \"equals\", value: true }\n      ],\n      result: {\n        value: {\n          level: 'admin' as const,\n          permissions: ['read', 'write', 'delete']\n        } as AccessRule\n      }\n    }\n  ],\n  default: {\n    value: {\n      level: 'guest' as const,\n      permissions: ['read']\n    } as AccessRule\n  }\n};\n\n// Type-safe evaluation\nconst result = await engine.evaluate<AccessRule>(accessRule, { \n  role: 'admin', \n  active: true \n});\n\nif (!Array.isArray(result)) {\n  console.log(result.value.level); // TypeScript knows this is 'admin' | 'user' | 'guest'\n  console.log(result.value.permissions); // TypeScript knows this is string[]\n}\n```\n\n## Custom Operators with Type Safety\n\nCreate type-safe custom operators:\n\n```typescript\nimport { BaseOperatorStrategy, OperatorMetadata, OperatorContext, OperatorCategory } from '@usex/rule-engine';\n\nclass EmailDomainOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata: OperatorMetadata = {\n    name: 'email-domain',\n    displayName: 'Email Domain',\n    category: OperatorCategory.STRING,\n    description: 'Checks if email has specific domain',\n    acceptedFieldTypes: ['string'],\n    expectedValueType: 'string',\n    requiresValue: true,\n    example: '{ field: \"email\", operator: \"email-domain\", value: \"gmail.com\" }'\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n    \n    if (typeof fieldValue !== 'string' || typeof constraintValue !== 'string') {\n      return false;\n    }\n    \n    const domain = fieldValue.split('@')[1];\n    return domain === constraintValue;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === 'string' && value.includes('@');\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === 'string' && !value.includes('@');\n  }\n}\n\n// Register the operator\nregisterCustomOperator(EmailDomainOperator);\n```\n\n## Common TypeScript Patterns\n\n### Pattern 1: Conditional Type Guards\n\n```typescript\nconst results = await engine.evaluate(rule, criteriaArray);\n\nif (Array.isArray(results)) {\n  // TypeScript knows results is Array<EvaluationResult<T>>\n  results.forEach(result => {\n    console.log(result.isPassed);\n  });\n} else {\n  // TypeScript knows results is EvaluationResult<T>\n  console.log(results.isPassed);\n}\n```\n\n### Pattern 2: Generic Constraints\n\n```typescript\ninterface BaseEntity {\n  id: string;\n  createdAt: Date;\n}\n\nasync function evaluateEntity<T extends BaseEntity>(\n  rule: RuleType,\n  entity: T\n): Promise<EvaluationResult<boolean>> {\n  return await engine.evaluate<boolean>(rule, entity);\n}\n```\n\n### Pattern 3: Type-Safe Mutations\n\n```typescript\n// Define mutation with proper types\nengine.addMutation<number>('doubleValue', (value: number) => value * 2);\n\n// Use in rules\nconst rule = {\n  conditions: {\n    and: [\n      { field: \"score\", operator: \"greater-than\", value: 50 }\n    ]\n  }\n};\n\n// The mutation will be applied to the score field\nconst result = await engine.evaluate(rule, { score: 30 }); // score becomes 60 after mutation\n```\n\n## Troubleshooting\n\n### Issue: \"Property isPassed does not exist on type EvaluationResult<any>[]\"\n\n**Solution**: This error occurs when TypeScript can't determine if the result is a single object or array. Use the overloaded methods or add type guards:\n\n```typescript\n// Option 1: Use specific criteria type\nconst result = await engine.evaluate(rule, { age: 25 } as CriteriaObject);\n\n// Option 2: Use type guard\nconst result = await engine.evaluate(rule, criteria);\nif (!Array.isArray(result)) {\n  console.log(result.isPassed); // Now TypeScript knows it's not an array\n}\n```\n\n### Issue: \"Constructor of class RuleEngine is private\"\n\n**Solution**: Use the singleton pattern:\n\n```typescript\n// ❌ Wrong\nconst engine = new RuleEngine();\n\n// ✅ Correct\nconst engine = RuleEngine.getInstance();\n```\n\n### Issue: Type inference not working in IDE\n\n**Solution**: \n1. Restart TypeScript language server\n2. Ensure you're importing from the correct path\n3. Check that your `tsconfig.json` includes the rule engine types\n\n### Issue: Custom operator types not recognized\n\n**Solution**: Ensure you're extending the correct base class and implementing all required methods:\n\n```typescript\nclass MyOperator extends BaseOperatorStrategy<FieldType, ConstraintType> {\n  // Implement all required methods\n  evaluate(context: OperatorContext): boolean { /* ... */ }\n  isValidFieldType(value: unknown): value is FieldType { /* ... */ }\n  isValidConstraintType(value: unknown): value is ConstraintType { /* ... */ }\n}\n```\n\n## Best Practices\n\n1. **Always specify generic types** when you know the result type:\n   ```typescript\n   const result = await engine.evaluate<MyResultType>(rule, criteria);\n   ```\n\n2. **Use const assertions** for literal types in rules:\n   ```typescript\n   result: { value: 'admin' as const }\n   ```\n\n3. **Leverage type guards** instead of type assertions:\n   ```typescript\n   if (!Array.isArray(result)) {\n     // TypeScript knows result is not an array\n   }\n   ```\n\n4. **Define interfaces** for complex rule results:\n   ```typescript\n   interface RuleResult {\n     status: string;\n     score: number;\n   }\n   ```\n\n5. **Use proper cleanup** in tests to avoid state pollution:\n   ```typescript\n   afterEach(() => {\n     engine.clearMutations();\n     engine.clearCache();\n   });\n   ```"
  },
  {
    "path": "packages/core/docs/v2-migration-guide.md",
    "content": "# Migration Guide: Upgrading to RuleEngine V2\n\nThis guide will help you migrate from the original RuleEngine to the new V2 implementation that uses the Strategy pattern for operators.\n\n> **Updated for v2.1**: This guide now includes information about TypeScript method overloads, improved type inference, and singleton pattern changes.\n\n## Table of Contents\n\n- [Overview of Changes](#overview-of-changes)\n- [Breaking Changes](#breaking-changes)\n- [New Features](#new-features)\n- [TypeScript Improvements (v2.1)](#typescript-improvements-v21)\n- [Migration Steps](#migration-steps)\n- [API Compatibility](#api-compatibility)\n- [Custom Operators](#custom-operators)\n- [Performance Improvements](#performance-improvements)\n\n## Overview of Changes\n\nRuleEngine V2 introduces significant architectural improvements:\n\n1. **Strategy Pattern for Operators**: All operators now use the Strategy pattern, making them more modular and extensible\n2. **Full Type Safety**: Enhanced TypeScript support with better type inference\n3. **Operator Registry**: Centralized management of operators with metadata\n4. **Enhanced Introspection**: More detailed rule analysis with operator metadata\n5. **Custom Operators**: Easy creation and registration of custom operators\n6. **Performance Optimizations**: Optional caching and lazy evaluation\n\n## Breaking Changes\n\n### 1. Import Changes\n\nIf you're importing specific operators:\n\n```typescript\n// Old\nimport { greaterThanOperator, equalsOperator } from \"@usex/rule-engine\";\n\n// New - operators are now classes\nimport { GreaterThanOperator, EqualsOperator } from \"@usex/rule-engine\";\n```\n\n### 2. Custom Operator Registration\n\nThe way to add custom operators has changed:\n\n```typescript\n// Old - directly modify operator map\n// New - use operator registry\nimport { registerCustomOperator, BaseOperatorStrategy } from \"@usex/rule-engine\";\n\noperatorsProcessorMap[\"custom-operator\"] = (a, b) => customLogic(a, b);\n\nclass CustomOperator extends BaseOperatorStrategy {\n  // Implementation\n}\n\nregisterCustomOperator(CustomOperator);\n```\n\n### 3. Introspection Result Structure\n\nEnhanced introspection now includes optional metadata:\n\n```typescript\n// Old\nconst result = RuleEngine.introspect(rule);\n// Returns: { results: [...], default?: {...} }\n\n// New\nconst result = RuleEngine.introspect(rule, {\n  includeMetadata: true,\n  includeComplexity: true\n});\n// Returns: Enhanced result with operator metadata and complexity metrics\n```\n\n## New Features\n\n### 1. RuleEngine Configuration\n\n```typescript\nimport { RuleEngine } from \"@usex/rule-engine\";\n\n// Configure the engine\nconst engine = RuleEngine.getInstance({\n  trustMode: true,              // Skip validation for trusted rules\n  enableCaching: true,          // Cache evaluation results\n  maxCacheSize: 1000,          // Maximum cache entries\n  enableOptimizations: true,    // Enable performance optimizations\n});\n```\n\n### 2. Operator Metadata and Validation\n\n```typescript\n// Get metadata for all operators\nconst registry = engine.getOperatorRegistry();\nconst allOperators = registry.getAllMetadata();\n\n// Validate operators in a rule\nconst validation = engine.validateOperators(rule);\nif (!validation.isValid) {\n  console.error(\"Invalid operators:\", validation.errors);\n}\n\n// Get operators used in a rule\nconst usedOperators = engine.getUsedOperators(rule);\n```\n\n### 3. Custom Operator Creation\n\n```typescript\nimport { registerCustomOperator, OperatorCategory, BaseOperatorStrategy } from \"@usex/rule-engine\";\n\nclass EmailDomainOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata = {\n    name: \"email-domain\",\n    displayName: \"Email Domain\",\n    category: OperatorCategory.STRING,\n    description: \"Checks if email has specific domain\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    example: '{ field: \"email\", operator: \"email-domain\", value: \"gmail.com\" }'\n  };\n\n  evaluate(context) {\n    const { fieldValue, constraintValue } = context;\n    if (!fieldValue || !constraintValue) return false;\n\n    const domain = fieldValue.split('@')[1];\n    return domain === constraintValue;\n  }\n\n  isValidFieldType(value) {\n    return typeof value === \"string\" && value.includes(\"@\");\n  }\n}\n\n// Register the operator\nregisterCustomOperator(EmailDomainOperator);\n```\n\n## TypeScript Improvements (v2.1)\n\n### 1. Method Overloads for Better Type Inference\n\nAll methods that accept `Criteria` now have overloads for automatic type inference:\n\n```typescript\n// Old - Union return type\nconst result = await engine.evaluate(rule, criteria);\n// result: EvaluationResult<T> | Array<EvaluationResult<T>>\n// TypeScript doesn't know which type without checking\n\n// New - Overloaded methods with specific return types\nconst singleResult = await engine.evaluate(rule, { age: 25 });\n// singleResult: EvaluationResult<T> - TypeScript knows it's a single result\n\nconst arrayResults = await engine.evaluate(rule, [{ age: 25 }, { age: 30 }]);\n// arrayResults: Array<EvaluationResult<T>> - TypeScript knows it's an array\n```\n\n### 2. Singleton Pattern Enforcement\n\nThe RuleEngine constructor is now private:\n\n```typescript\n// Old - Direct instantiation\nconst engine = new RuleEngine();\n\n// New - Singleton pattern\nconst engine = RuleEngine.getInstance();\n```\n\n### 3. Enhanced Mutation Management\n\nThe `clearMutations()` method now properly removes all mutations:\n\n```typescript\n// Old - Only cleared cache\nengine.clearMutations(); // Only cleared mutation cache\n\n// New - Removes all mutations\nengine.clearMutations(); // Removes all registered mutations\nengine.clearMutationCache(); // Clears only the cache\n```\n\n### 4. Message Priority Fix\n\nConstraint-specific error messages now have proper priority:\n\n```typescript\n// Old behavior - Default rule message had priority\n// When a constraint failed, the rule's default message was returned\n\n// New behavior - Constraint message has priority\n// When a constraint fails, its specific message is returned\nconst rule = {\n  conditions: {\n    and: [\n      { \n        field: \"length\", \n        operator: \"length-between\", \n        value: [4, 20],\n        message: \"Length must be between 4 and 20 characters\"\n      }\n    ]\n  },\n  default: { message: \"Rule failed\" }\n};\n\n// Now returns: \"Length must be between 4 and 20 characters\"\n// Instead of: \"Rule failed\"\n```\n\n## Migration Steps\n\n### Step 1: Update Imports\n\n```typescript\n// Update your imports to use V2\nimport { RuleEngine } from \"@usex/rule-engine\";\n\n// Or use both during migration\nimport { RuleEngine,  } from \"@usex/rule-engine\";\n```\n\n### Step 2: Update Rule Evaluation Calls\n\nThe API is mostly compatible, but you can now use the enhanced version:\n\n```typescript\n// Old\nconst result = await RuleEngine.evaluate(rule, data);\n\n// New - same API, but using V2\nconst result = await RuleEngine.evaluate(rule, data);\n\n// With configuration\nconst engine = RuleEngine.getInstance({ enableCaching: true });\nconst result = await engine.evaluate(rule, data);\n```\n\n### Step 3: Update Custom Operators\n\nIf you have custom operators, migrate them to the new pattern:\n\n```typescript\n// Old custom operator\nconst customOperator = (fieldValue, constraintValue) => {\n  return fieldValue > constraintValue * 2;\n};\n\n// New custom operator\nclass CustomMultiplierOperator extends BaseOperatorStrategy<number, number> {\n  readonly metadata = {\n    name: \"greater-than-double\",\n    displayName: \"Greater Than Double\",\n    category: OperatorCategory.NUMERIC,\n    description: \"Checks if field is greater than double the value\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n  };\n\n  evaluate(context) {\n    const { fieldValue, constraintValue } = context;\n    return fieldValue > constraintValue * 2;\n  }\n\n  isValidFieldType(value) {\n    return typeof value === \"number\";\n  }\n}\n\nregisterCustomOperator(CustomMultiplierOperator);\n```\n\n### Step 4: Update Introspection Usage\n\n```typescript\n// Old\nconst introspection = RuleEngine.introspect(rule);\n\n// New with enhanced features\nconst introspection = RuleEngine.introspect(rule, {\n  includeMetadata: true,    // Include operator metadata\n  includeComplexity: true,  // Include complexity metrics\n  validateOperators: true   // Validate all operators exist\n});\n\n// Access new metadata\nconsole.log(\"Used operators:\", introspection.operatorMetadata?.usedOperators);\nconsole.log(\"Complexity:\", introspection.complexity);\n```\n\n## API Compatibility\n\n### Fully Compatible APIs\n\nThese methods work exactly the same in V2:\n\n- `evaluate(rule, criteria, trustRule?)`\n- `checkIsPassed(rule, criteria, trustRule?)`\n- `getEvaluateResult(rule, criteria, trustRule?)`\n- `validate(rule)`\n- `builder()`\n\n### Enhanced APIs\n\nThese methods have additional optional features in V2:\n\n- `introspect(rule, options?)` - Now accepts options for metadata and complexity\n- `constructor/getInstance(config?)` - Now accepts configuration options\n\n### New APIs in V2\n\n- `validateOperators(rule)` - Validate all operators in a rule\n- `getUsedOperators(rule)` - Get set of operators used\n- `getOperatorRegistry()` - Access the operator registry\n- `configure(config)` - Update configuration\n- `clearCache()` - Clear evaluation cache\n\n## Custom Operators\n\n### Operator Interface\n\nAll operators must implement the `OperatorStrategy` interface:\n\n```typescript\ninterface OperatorStrategy<TField = any, TValue = any> {\n  readonly metadata: OperatorMetadata;\n  validate(context: OperatorContext): ValidationResult;\n  evaluate(context: OperatorContext): boolean;\n  isValidFieldType?(value: unknown): value is TField;\n  isValidConstraintType?(value: unknown): value is TValue;\n  formatMessage?(template: string, context: OperatorContext): string;\n}\n```\n\n### Operator Context\n\nOperators receive a context object with:\n\n```typescript\ninterface OperatorContext {\n  fieldValue: any;          // The resolved field value\n  constraintValue?: any;    // The constraint value\n  criteria?: Record<string, any>;  // Full criteria object\n  fieldPath?: string;       // The field path\n}\n```\n\n### Best Practices for Custom Operators\n\n1. **Extend BaseOperatorStrategy**: Provides default implementations\n2. **Implement Type Guards**: Use `isValidFieldType` and `isValidConstraintType`\n3. **Provide Clear Metadata**: Help users understand your operator\n4. **Handle Edge Cases**: Null, undefined, type mismatches\n5. **Add Validation**: Implement custom validation logic\n\n## Performance Improvements\n\n### 1. Enable Caching\n\n```typescript\nconst engine = RuleEngine.getInstance({\n  enableCaching: true,\n  maxCacheSize: 1000\n});\n\n// Clear cache when needed\nengine.clearCache();\n```\n\n### 2. Trust Mode\n\nSkip validation for known-good rules:\n\n```typescript\n// Global trust mode\nconst engine = RuleEngine.getInstance({ trustMode: true });\n\n// Per-evaluation trust\nawait engine.evaluate(rule, data, true); // Skip validation\n```\n\n### 3. Operator Registry\n\nThe registry enables:\n- Fast operator lookup (O(1) instead of O(n))\n- Lazy loading of operators\n- Better memory management\n\n## Troubleshooting\n\n### Common Issues\n\n1. **\"Unknown operator\" errors**\n   - Ensure custom operators are registered before use\n   - Check operator names match exactly (case-sensitive)\n\n2. **Type errors with custom operators**\n   - Implement proper type guards\n   - Use generics for type safety\n\n3. **Performance degradation**\n   - Enable caching for repeated evaluations\n   - Use trust mode for validated rules\n   - Consider batch evaluation for multiple items\n\n### Debug Mode\n\nEnable debug logging:\n\n```typescript\nimport { Logger } from \"@usex/rule-engine\";\nLogger.setLevel(\"debug\");\n```\n\n## Example: Complete Migration\n\n```typescript\n// Before\nimport { RuleEngine } from \"@usex/rule-engine\";\n\n// After\nimport { RuleEngine, initializeOperators } from \"@usex/rule-engine\";\n\nconst rule = {\n  conditions: {\n    and: [\n      { field: \"age\", operator: \"greater-than\", value: 18 },\n      { field: \"status\", operator: \"equals\", value: \"active\" }\n    ]\n  }\n};\n\nconst result = await RuleEngine.evaluate(rule, { age: 25, status: \"active\" });\n\n// Initialize once at app startup\ninitializeOperators();\n\n// Configure engine\nconst engine = RuleEngine.getInstance({\n  enableCaching: true,\n  trustMode: false\n});\n\n// Same rule works without changes\nconst result = await engine.evaluate(rule, { age: 25, status: \"active\" });\n\n// Use new features\nconst introspection = await engine.introspect(rule, {\n  includeMetadata: true,\n  includeComplexity: true\n});\n\nconsole.log(\"Rule complexity:\", introspection.complexity);\nconsole.log(\"Operators used:\", introspection.operatorMetadata?.usedOperators);\n```\n\n## Summary\n\nRuleEngine V2 maintains backward compatibility while adding powerful new features. The migration can be done incrementally:\n\n1. Start by updating imports to use RuleEngine\n2. Gradually migrate custom operators to the new pattern\n3. Take advantage of new features like caching and enhanced introspection\n4. Consider using TypeScript for better type safety\n\nThe original RuleEngine remains available for backward compatibility, allowing you to migrate at your own pace.\n"
  },
  {
    "path": "packages/core/package.json",
    "content": "{\n  \"name\": \"@usex/rule-engine\",\n  \"type\": \"module\",\n  \"version\": \"0.0.2\",\n  \"packageManager\": \"pnpm@10.17.1\",\n  \"description\": \"The ultimate JSON-based rule engine that turns complex business logic into declarative configurations. Built for developers who believe code should be expressive, not repetitive.\",\n  \"author\": {\n    \"name\": \"Ali Torki\",\n    \"email\": \"ali_4286@live.com\",\n    \"url\": \"https://github.com/ali-master\"\n  },\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/ali-master/rule-engine.git\",\n    \"directory\": \"packages/core\"\n  },\n  \"keywords\": [\n    \"rule-engine\",\n    \"business-rules\",\n    \"json-rules\",\n    \"typescript\",\n    \"validation\",\n    \"decision-engine\",\n    \"rules-processor\",\n    \"jsonpath\",\n    \"conditional-logic\",\n    \"form-validation\",\n    \"access-control\",\n    \"discount-engine\",\n    \"workflow\",\n    \"nodejs\",\n    \"browser\",\n    \"operators\",\n    \"expressions\"\n  ],\n  \"sideEffects\": false,\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/esm/index.js\",\n      \"require\": \"./dist/index.js\"\n    }\n  },\n  \"main\": \"dist/index.js\",\n  \"module\": \"dist/esm/index.js\",\n  \"typings\": \"dist/index.d.ts\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"engines\": {\n    \"node\": \">=18.12.0\"\n  },\n  \"scripts\": {\n    \"start\": \"nodemon ./dist/index.js --watch\",\n    \"dev\": \"tsup-node --watch\",\n    \"build\": \"tsup-node\",\n    \"test\": \"cross-env CI=true vitest --typecheck\",\n    \"test:junit\": \"cross-env CI=true vitest --reporter=junit --outputFile=test-report.junit.xml --typecheck\",\n    \"test:watch\": \"pnpm run test --watch\",\n    \"test:ui\": \"pnpm run test:watch --ui --coverage.enabled=true\",\n    \"test:bench\": \"cross-env CI=true vitest bench\",\n    \"test:coverage\": \"pnpm run test run --coverage\",\n    \"test:debug\": \"vitest --inspect-brk --pool forks --poolOptions.forks.singleFork\",\n    \"test:debug:watch\": \"pnpm run test:debug --watch --poolOptions.threads.isolate false\",\n    \"inspect\": \"node-modules-inspector\",\n    \"test:types\": \"tsc --noEmit\",\n    \"test:knip\": \"knip\",\n    \"test:knip:fix\": \"knip --fix\",\n    \"format:check\": \"prettier --check \\\"**/*.{ts,tsx,mdx}\\\"\",\n    \"format\": \"prettier --write \\\"**/*.{ts,tsx,mdx}\\\"\",\n    \"lint\": \"eslint \\\"src/**/*.ts\\\"\",\n    \"lint:fix\": \"pnpm run lint --fix\",\n    \"prepublishOnly\": \"pnpm lint && pnpm test\",\n    \"prerelease\": \"pnpm run test\",\n    \"release\": \"cross-env CI=true pnpm run build\",\n    \"postrelease\": \"standard-version && pnpm publish --access public && git push --follow-tags origin master\",\n    \"release:beta\": \"pnpm run build\",\n    \"postrelease:beta\": \"standard-version --prerelease beta && pnpm publish --access public --tag beta && git push --follow-tags origin master\"\n  },\n  \"peerDependencies\": {\n    \"@persian-tools/persian-tools\": \"^3.6.0\",\n    \"date-fns\": \"^4.1.0\",\n    \"eventemitter3\": \"^5.0.1\",\n    \"jsonpath-plus\": \"^10.3.0\",\n    \"ramda\": \"^0.30.1\"\n  },\n  \"devDependencies\": {\n    \"@types/ramda\": \"^0.31.1\",\n    \"axios\": \"^1.12.2\",\n    \"tsup\": \"^8.5.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/core/src/enums/condition-types.enum.ts",
    "content": "// Purpose: Enumerates the types of logical operators that can be used to combine multiple criteria.\nexport enum ConditionTypes {\n  OR = \"or\", // Logical OR operator. If any condition is true, the result is true. Otherwise, the result is false.\n  AND = \"and\", // Logical AND operator. If all conditions are true, the result is true. Otherwise, the result is false.\n  NONE = \"none\", // Logical NOT operator. If no conditions are true, the result is true. Otherwise, the result is false.\n}\n"
  },
  {
    "path": "packages/core/src/enums/index.ts",
    "content": "export * from \"./condition-types.enum\";\nexport * from \"./operators.enum\";\n"
  },
  {
    "path": "packages/core/src/enums/operators.enum.ts",
    "content": "export enum Operators {\n  // Comparison Operators on Strings\n  Equals = \"equals\", // Check if the field value is equal to the provided value. The comparison is case-sensitive. The value must be a string. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"equals\", \"value\": \"John Doe\" } will check if the name field is equal to \"John Doe\".\n  NotEquals = \"not-equals\", // Check if the field value is not equal to the provided value. The comparison is case-sensitive. The value must be a string. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-equals\", \"value\": \"John Doe\" } will check if the name field is not equal to \"John Doe\".\n  Like = \"like\", // Check if the field value is like the provided value. The comparison is case-insensitive. The value must be a string. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"like\", \"value\": \"john\" } will check if the name field is like \"john\".\n  NotLike = \"not-like\", // Check if the field value is not like the provided value. The comparison is case-insensitive. The value must be a string. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-like\", \"value\": \"john\" } will check if the name field is not like \"john\".\n  StartsWith = \"starts-with\", // Check if the field value starts with the provided value. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"starts-with\", \"value\": \"John\" } will check if the name field starts with \"John\".\n  EndsWith = \"ends-with\", // Check if the field value ends with the provided value. The field value must be a string. Example: { \"field\": \"email\", \"operator\": \"ends-with\", \"value\": \".com\" } will check if the email field ends with \".com\".\n  ContainsString = \"contains-string\", // Check if the field value contains the provided substring. The field value must be a string. Example: { \"field\": \"description\", \"operator\": \"contains-string\", \"value\": \"error\" } will check if the description field contains \"error\".\n  // Comparison Operators on Numbers\n  GreaterThan = \"greater-than\", // Check if the field value is greater than the provided value. The value must be a number. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"greater-than\", \"value\": 18 } will check if the age field is greater than 18.\n  LessThan = \"less-than\", // Check if the field value is less than the provided value. The value must be a number. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"less-than\", \"value\": 18 } will check if the age field is less than 18.\n  GreaterThanOrEquals = \"greater-than-or-equals\", // Check if the field value is greater than or equal to the provided value. The value must be a number. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"greater-than-or-equals\", \"value\": 18 } will check if the age field is greater than or equal to 18.\n  LessThanOrEquals = \"less-than-or-equals\", // Check if the field value is less than or equal to the provided value. The value must be a number. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"less-than-or-equals\", \"value\": 18 } will check if the age field is less than or equal to 18.\n  // Comparison Operators on Arrays\n  In = \"in\", // Check if the field value is in the provided array of values. The values must be an array. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"in\", \"value\": [\"John Doe\", \"Jane Doe\"] } will check if the name field is in [\"John Doe\", \"Jane Doe\"].\n  NotIn = \"not-in\", // Check if the field value is not in the provided array of values. The values must be an array. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-in\", \"value\": [\"John Doe\", \"Jane Doe\"] } will check if the name field is not in [\"John Doe\", \"Jane Doe\"].\n  Contains = \"contains\", // Check if the field value contains the provided value. The comparison is case-sensitive. The value must be a string. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"contains\", \"value\": \"John\" } will check if the name field contains \"John\".\n  NotContains = \"not-contains\", // Check if the field value does not contain the provided value. The comparison is case-sensitive. The value must be a string. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-contains\", \"value\": \"John\" } will check if the name field does not contain \"John\".\n  ContainsAny = \"contains-any\", // Check if the field value contains any of the provided values. The values must be an array. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"contains-any\", \"value\": [\"John\", \"Jane\"] } will check if the name field contains any of [\"John\", \"Jane\"].\n  SelfContainsAny = \"self-contains-any\", // Check if the field value contains any of the values in the provided array. The values must be an array. The field value must be an array. Example: { \"field\": \"tags\", \"operator\": \"self-contains-any\", \"value\": [\"tag1\", \"tag2\"] } will check if the tags field contains any of [\"tag1\", \"tag2\"].\n  NotContainsAny = \"not-contains-any\", // Check if the field value does not contain any of the provided values. The values must be an array. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-contains-any\", \"value\": [\"John\", \"Jane\"] } will check if the name field does not contain any of [\"John\", \"Jane\"].\n  SelfNotContainsAny = \"self-not-contains-any\", // Check if the field value does not contain any of the values in the provided array. The values must be an array. The field value must be an array. Example: { \"field\": \"tags\", \"operator\": \"self-not-contains-any\", \"value\": [\"tag1\", \"tag2\"] } will check if the tags field does not contain any of [\"tag1\", \"tag2\"].\n  SelfContainsNone = \"self-not-contains-none\", // Check if the field value does not contain any of the values in the provided array. The values must be an array. The field value must be an array. Example: { \"field\": \"tags\", \"operator\": \"self-not-contains-none\", \"value\": [\"tag1\", \"tag2\"] } will check if the tags field does not contain any of [\"tag1\", \"tag2\"].\n  ContainsAll = \"contains-all\", // Check if the field value contains all the provided values. The values must be an array. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"contains-all\", \"value\": [\"John\", \"Doe\"] } will check if the name field contains all of [\"John\", \"Doe\"].\n  SelfContainsAll = \"self-contains-all\", // Check if the field value contains all the values in the provided array. The values must be an array. The field value must be an array. Example: { \"field\": \"tags\", \"operator\": \"self-contains-all\", \"value\": [\"tag1\", \"tag2\"] } will check if the tags field contains all of [\"tag1\", \"tag2\"].\n  NotContainsAll = \"not-contains-all\", // Check if the field value does not contain all the provided values. The values must be an array. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-contains-all\", \"value\": [\"John\", \"Doe\"] } will check if the name field does not contain all of [\"John\", \"Doe\"].\n  SelfNotContainsAll = \"self-not-contains-all\", // Check if the field value does not contain all the values in the provided array. The values must be an array. The field value must be an array. Example: { \"field\": \"tags\", \"operator\": \"self-not-contains-all\", \"value\": [\"tag1\", \"tag2\"] } will check if the tags field does not contain all of [\"tag1\", \"tag2\"].\n  // Comparison Operators on Strings (Regular Expressions)\n  Matches = \"matches\", // Check if the field value matches the provided regular expression. The value must be a string. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"matches\", \"value\": \"John\" } will check if the name field matches the regular expression \"John\".\n  NotMatches = \"not-matches\", // Check if the field value does not match the provided regular expression. The value must be a string. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-matches\", \"value\": \"John\" } will check if the name field does not match the regular expression \"John\".\n  // Existence Operators on Fields and Relationships\n  Exists = \"exists\", // Check if the field exists in the object. The field must be a string. Example: { \"field\": \"name\", \"operator\": \"exists\" } will check if the name field exists in the object.\n  NotExists = \"not-exists\", // Check if the field does not exist in the object. The field must be a string. Example: { \"field\": \"name\", \"operator\": \"not-ex\n  // Nullability Operators on Fields and Relationships\n  NullOrUndefined = \"null-or-undefined\", // Check if the field value is null or undefined. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"null-or-undefined\" } will check if the name field value is null or undefined.\n  NotNullOrUndefined = \"not-null-or-undefined\", // Check if the field value is not null or undefined. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-null-or-undefined\" } will check if the name field value is not null or undefined.\n  Empty = \"empty\", // Check if the field value is empty. The field value must be string, array or object. Example: { \"field\": \"name\", \"operator\": \"empty\" } will check if the name field value is empty.\n  NotEmpty = \"not-empty\", // Check if the field value is not empty. The field value must be string, array or object. Example: { \"field\": \"name\", \"operator\": \"not-empty\" } will check if the name field value is not empty.\n  // Comparison Operators on Dates and Times\n  DateAfter = \"date-after\", // Check if the field value is after the provided date. The value must be a date. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-after\", \"value\": \"2021-01-01\" } will check if the date field is after \"2021-01-01\".\n  DateAfterNow = \"date-after-now\", // Check if the field value is after the current date and time. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-after-now\" } will check if the date field is after the current date and time.\n  DateBefore = \"date-before\", // Check if the field value is before the provided date. The value must be a date. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-before\", \"value\": \"2021-01-01\" } will check if the date field is before \"2021-01-01\".\n  DateBeforeNow = \"date-before-now\", // Check if the field value is before the current date and time. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-before-now\" } will check if the date field is before the current date and time.\n  DateAfterOrEquals = \"date-after-or-equals\", // Check if the field value is after or equal to the provided date. The value must be a date. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-after-or-equals\", \"value\": \"2021-01-01\" } will check if the date field is after or equal to \"2021-01-01\".\n  DateAfterNowOrEquals = \"date-after-now-or-equals\", // Check if the field value is after or equal to the current date and time. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-after-now-or-equals\" } will check if the date field is after or equal to the current date and time.\n  DateBeforeOrEquals = \"date-before-or-equals\", // Check if the field value is before or equal to the provided date. The value must be a date. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-before-or-equals\", \"value\": \"2021-01-01\" } will check if the date field is before or equal to \"2021-01-01\".\n  DateBeforeNowOrEquals = \"date-before-now-or-equals\", // Check if the field value is before or equal to the current date and time. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-before-now-or-equals\" } will check if the date field is before or equal to the current date and time.\n  DateEquals = \"date-equals\", // Check if the field value is equal to the provided date. The value must be a date. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-equals\", \"value\": \"2021-01-01\" } will check if the date field is equal to \"2021-01-01\".\n  DateEqualsToNow = \"date-equals-to-now\", // Check if the field value is equal to the current date and time. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-equals-to-now\" } will check if the date field is equal to the current date and time.\n  DateNotEquals = \"date-not-equals\", // Check if the field value is not equal to the provided date. The value must be a date. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-not-equals\", \"value\": \"2021-01-01\" } will check if the date field is not equal to \"2021-01-01\".\n  DateNotEqualsToNow = \"date-not-equals-to-now\", // Check if the field value is not equal to the current date and time. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-not-equals-to-now\" } will check if the date field is not equal to the current date and time.\n  DateBetween = \"date-between\", // Check if the field value is between the provided dates. The values must be an array of two dates. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-between\", \"value\": [\"2021-01-01\", \"2021-12-31\"] } will check if the date field is between \"2021-01-01\" and \"2021-12-31\".\n  DateNotBetween = \"date-not-between\", // Check if the field value is not between the provided dates. The values must be an array of two dates. The field value must be a date. Example: { \"field\": \"date\", \"operator\": \"date-not-between\", \"value\": [\"2021-01-01\", \"2021-12-31\"] } will check if the date field is not between \"2021-01-01\" and \"2021-12-31\".\n  TimeAfter = \"time-after\", // Check if the field value is after the provided time. The value must be a time. The field value must be a time. Example: { \"field\": \"time\", \"operator\": \"time-after\", \"value\": \"12:00:00\" } will check if the time field is after \"12:00:00\".\n  TimeBefore = \"time-before\", // Check if the field value is before the provided time. The value must be a time. The field value must be a time. Example: { \"field\": \"time\", \"operator\": \"time-before\", \"value\": \"12:00:00\" } will check if the time field is before \"12:00:00\".\n  TimeAfterOrEquals = \"time-after-or-equals\", // Check if the field value is after or equal to the provided time. The value must be a time. The field value must be a time. Example: { \"field\": \"time\", \"operator\": \"time-after-or-equals\", \"value\": \"12:00:00\" } will check if the time field is after or equal to \"12:00:00\".\n  TimeBeforeOrEquals = \"time-before-or-equals\", // Check if the field value is before or equal to the provided time. The value must be a time. The field value must be a time. Example: { \"field\": \"time\", \"operator\": \"time-before-or-equals\", \"value\": \"12:00:00\" } will check if the time field is before or equal to \"12:00:00\".\n  TimeEquals = \"time-equals\", // Check if the field value is equal to the provided time. The value must be a time. The field value must be a time. Example: { \"field\": \"time\", \"operator\": \"time-equals\", \"value\": \"12:00:00\" } will check if the time field is equal to \"12:00:00\".\n  TimeNotEquals = \"time-not-equals\", // Check if the field value is not equal to the provided time. The value must be a time. The field value must be a time. Example: { \"field\": \"time\", \"operator\": \"time-not-equals\", \"value\": \"12:00:00\" } will check if the time field is not equal to \"12:00:00\".\n  TimeBetween = \"time-between\", // Check if the field value is between the provided times. The values must be an array of two times. The field value must be a time. Example: { \"field\": \"time\", \"operator\": \"time-between\", \"value\": [\"08:00:00\", \"17:00:00\"] } will check if the time field is between \"08:00:00\" and \"17:00:00\".\n  TimeNotBetween = \"time-not-between\", // Check if the field value is not between the provided times. The values must be an array of two times. The field value must be a time. Example: { \"field\": \"time\", \"operator\": \"time-not-between\", \"value\": [\"08:00:00\", \"17:00:00\"] } will check if the time field is not between \"08:00:00\" and \"17:00:00\".\n  // Logical Operators\n  NullOrWhiteSpace = \"null-or-white-space\", // Check if the field value is null or white space. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"null-or-white-space\" } will check if the name field value is null or white space.\n  NotNullOrWhiteSpace = \"not-null-or-white-space\", // Check if the field value is not null or white space. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-null-or-white-space\" } will check if the name field value is not null or white space.\n  Numeric = \"numeric\", // Check if the field value is numeric. The field value must be a string. Example: { \"field\": \"age\", \"operator\": \"numeric\" } will check if the age field value is numeric.\n  NotNumeric = \"not-numeric\", // Check if the field value is not numeric. The field value must be a string. Example: { \"field\": \"age\", \"operator\": \"not-numeric\" } will check if the age field value is not numeric.\n  Boolean = \"boolean\", // Check if the field value is boolean. The field value must be a string. Example: { \"field\": \"active\", \"operator\": \"boolean\" } will check if the active field value is boolean.\n  NotBoolean = \"not-boolean\", // Check if the field value is not boolean. The field value must be a string. Example: { \"field\": \"active\", \"operator\": \"not-boolean\" } will check if the active field value is not boolean.\n  Date = \"date\", // Check if the field value is a date. The field value must be a string. Example: { \"field\": \"date\", \"operator\": \"date\" } will check if the date field value is a date.\n  NotDate = \"not-date\", // Check if the field value is not a date. The field value must be a string. Example: { \"field\": \"date\", \"operator\": \"not-date\" } will check if the date field value is not a date.\n  Email = \"email\", // Check if the field value is an email. The field value must be a string. Example: { \"field\": \"email\", \"operator\": \"email\" } will check if the email field value is an email.\n  NotEmail = \"not-email\", // Check if the field value is not an email. The field value must be a string. Example: { \"field\": \"email\", \"operator\": \"not-email\" } will check if the email field value is not an email.\n  Url = \"url\", // Check if the field value is a URL. The field value must be a string. Example: { \"field\": \"url\", \"operator\": \"url\" } will check if the url field value is a URL.\n  NotUrl = \"not-url\", // Check if the field value is not a URL. The field value must be a string. Example: { \"field\": \"url\", \"operator\": \"not-url\" } will check if the url field value is not a URL.\n  UUID = \"uuid\", // Check if the field value is a UUID. The field value must be a string. Example: { \"field\": \"uuid\", \"operator\": \"uuid\" } will check if the uuid field value is a UUID.\n  NotUUID = \"not-uuid\", // Check if the field value is not a UUID. The field value must be a string. Example: { \"field\": \"uuid\", \"operator\": \"not-uuid\" } will check if the uuid field value is not a UUID.\n  Alpha = \"alpha\", // Check if the field value is alpha. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"alpha\" } will check if the name field value is alpha.\n  NotAlpha = \"not-alpha\", // Check if the field value is not alpha. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-alpha\" } will check if the name field value is not alpha.\n  AlphaNumeric = \"alpha-numeric\", // Check if the field value is alpha-numeric. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"alpha-numeric\" } will check if the name field value is alpha-numeric.\n  NotAlphaNumeric = \"not-alpha-numeric\", // Check if the field value is not alpha-numeric. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-alpha-numeric\" } will check if the name field value is not alpha-numeric.\n  PersianAlpha = \"persian-alpha\", // Check if the field value is Persian alpha. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"persian-alpha\" } will check if the name field value is Persian alpha.\n  NotPersianAlpha = \"not-persian-alpha\", // Check if the field value is not Persian alpha. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-persian-alpha\" } will check if the name field value is not Persian alpha.\n  PersianAlphaNumeric = \"persian-alpha-numeric\", // Check if the field value is Persian alpha-numeric. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"persian-alpha-numeric\" } will check if the name field value is Persian alpha-numeric.\n  NotPersianAlphaNumeric = \"not-persian-alpha-numeric\", // Check if the field value is not Persian alpha-numeric. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-persian-alpha-numeric\" } will check if the name field value is not Persian alpha-numeric.\n  LowerCase = \"lower-case\", // Check if the field value is lower case. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"lower-case\" } will check if the name field value is lower case.\n  NotLowerCase = \"not-lower-case\", // Check if the field value is not lower case. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-lower-case\" } will check if the name field value is not lower case.\n  UpperCase = \"upper-case\", // Check if the field value is upper case. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"upper-case\" } will check if the name field value is upper case.\n  NotUpperCase = \"not-upper-case\", // Check if the field value is not upper case. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-upper-case\" } will check if the name field value is not upper case.\n  String = \"string\", // Check if the field value is a string. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"string\" } will check if the name field value is a string.\n  NotString = \"not-string\", // Check if the field value is not a string. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-string\" } will check if the name field value is not a string.\n  Object = \"object\", // Check if the field value is an object. The field value must be an object. Example: { \"field\": \"user\", \"operator\": \"object\" } will check if the user field value is an object.\n  NotObject = \"not-object\", // Check if the field value is not an object. The field value must be an object. Example: { \"field\": \"user\", \"operator\": \"not-object\" } will check if the user field value is not an object.\n  Array = \"array\", // Check if the field value is an array. The field value must be an array. Example: { \"field\": \"tags\", \"operator\": \"array\" } will check if the tags field value is an array.\n  NotArray = \"not-array\", // Check if the field value is not an array. The field value must be an array. Example: { \"field\": \"tags\", \"operator\": \"not-array\" } will check if the tags field value is not an array.\n  ArrayLength = \"array-length\", // Check if the array length equals the specified value. The field value must be an array. Example: { \"field\": \"items\", \"operator\": \"array-length\", \"value\": 5 } will check if the items field has exactly 5 elements.\n  ArrayMinLength = \"array-min-length\", // Check if the array length is at least the specified value. The field value must be an array. Example: { \"field\": \"attendees\", \"operator\": \"array-min-length\", \"value\": 2 } will check if the attendees field has at least 2 elements.\n  ArrayMaxLength = \"array-max-length\", // Check if the array length is at most the specified value. The field value must be an array. Example: { \"field\": \"tags\", \"operator\": \"array-max-length\", \"value\": 10 } will check if the tags field has at most 10 elements.\n  BooleanString = \"boolean-string\", // Check if the field value is a boolean string. The field value must be a string. Example: { \"field\": \"active\", \"operator\": \"boolean-string\" } will check if the active field value is a boolean string.\n  NotBooleanString = \"not-boolean-string\", // Check if the field value is not a boolean string. The field value must be a string. Example: { \"field\": \"active\", \"operator\": \"not-boolean-string\" } will check if the active field value is not a boolean string.\n  BooleanNumber = \"boolean-number\", // Check if the field value is a boolean number. The field value must be a number. Example: { \"field\": \"active\", \"operator\": \"boolean-number\" } will check if the active field value is a boolean number.\n  NotBooleanNumber = \"not-boolean-number\", // Check if the field value is not a boolean number. The field value must be a number. Example: { \"field\": \"active\", \"operator\": \"not-boolean-number\" } will check if the active field value is not a boolean number.\n  BooleanNumberString = \"boolean-number-string\", // Check if the field value is a boolean number string. The field value must be a string. Example: { \"field\": \"active\", \"operator\": \"boolean-number-string\" } will check if the active field value is a boolean number string.\n  NotBooleanNumberString = \"not-boolean-number-string\", // Check if the field value is not a boolean number string. The field value must be a string. Example: { \"field\": \"active\", \"operator\": \"not-boolean-number-string\" } will check if the active field value is not a boolean number string.\n  Number = \"number\", // Check if the field value is a number. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"number\" } will check if the age field value is a number.\n  NotNumber = \"not-number\", // Check if the field value is not a number. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"not-number\" } will check if the age field value is not a number.\n  Integer = \"integer\", // Check if the field value is an integer. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"integer\" } will check if the age field value is an integer.\n  NotInteger = \"not-integer\", // Check if the field value is not an integer. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"not-integer\" } will check if the age field value is not an integer.\n  Float = \"float\", // Check if the field value is a float. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"float\" } will check if the age field value is a float.\n  NotFloat = \"not-float\", // Check if the field value is not a float. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"not-float\" } will check if the age field value is not a float.\n  Positive = \"positive\", // Check if the field value is positive. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"positive\" } will check if the age field value is positive.\n  NotPositive = \"not-positive\", // Check if the field value is not positive. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"not-positive\" } will check if the age field value is not positive.\n  Negative = \"negative\", // Check if the field value is negative. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"negative\" } will check if the age field value is negative.\n  NotNegative = \"not-negative\", // Check if the field value is not negative. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"not-negative\" } will check if the age field value is not negative.\n  Zero = \"zero\", // Check if the field value is zero. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"zero\" } will check if the age field value is zero.\n  NotZero = \"not-zero\", // Check if the field value is not zero. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"not-zero\" } will check if the age field value is not zero.\n  Min = \"min\", // Check if the field value is greater than or equal to the provided value. The value must be a number. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"min\", \"value\": 18 } will check if the age field value is greater than or equal to 18.\n  NotMin = \"not-min\", // Check if the field value is less than the provided value. The value must be a number. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"not-min\", \"value\": 18 } will check if the age field value is less than 18.\n  Max = \"max\", // Check if the field value is less than or equal to the provided value. The value must be a number. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"max\", \"value\": 65 } will check if the age field value is less than or equal to 65.\n  NotMax = \"not-max\", // Check if the field value is greater than the provided value. The value must be a number. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"not-max\", \"value\": 65 } will check if the age field value is greater than 65.\n  Between = \"between\", // Check if the field value is between the provided values. The values must be an array of two numbers. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"between\", \"value\": [18, 65] } will check if the age field value is between 18 and 65.\n  NotBetween = \"not-between\", // Check if the field value is not between the provided values. The values must be an array of two numbers. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"not-between\", \"value\": [18, 65] } will check if the age field value is not between 18 and 65.\n  NumberBetween = \"number-between\", // Check if the field value is between the provided values. The values must be an array of two numbers. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"number-between\", \"value\": [18, 65] } will check if the age field value is between 18 and 65.\n  NotNumberBetween = \"not-number-between\", // Check if the field value is not between the provided values. The values must be an array of two numbers. The field value must be a number. Example: { \"field\": \"age\", \"operator\": \"not-number-between\", \"value\": [18, 65] } will check if the age field value is not between 18 and 65.\n  StringLength = \"string-length\", // Check if the field value length is equal to the provided value. The value must be a number. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"string-length\", \"value\": 4 } will check if the name field value length is equal to 4.\n  NotStringLength = \"not-string-length\", // Check if the field value length is not equal to the provided value. The value must be a number. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-string-length\", \"value\": 4 } will check if the name field value length is not equal to 4.\n  MinLength = \"min-length\", // Check if the field value length is greater than or equal to the provided value. The value must be a number. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"min-length\", \"value\": 4 } will check if the name field value length is greater than or equal to 4.\n  NotMinLength = \"not-min-length\", // Check if the field value length is less than the provided value. The value must be a number. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-min-length\", \"value\": 4 } will check if the name field value length is less than 4.\n  MaxLength = \"max-length\", // Check if the field value length is less than or equal to the provided value. The value must be a number. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"max-length\", \"value\": 4 } will check if the name field value length is less than or equal to 4.\n  NotMaxLength = \"not-max-length\", // Check if the field value length is greater than the provided value. The value must be a number. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-max-length\", \"value\": 4 } will check if the name field value length is greater than 4.\n  LengthBetween = \"length-between\", // Check if the field value length is between the provided values. The values must be an array of two numbers. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"between-length\", \"value\": [4, 8] } will check if the name field value length is between 4 and 8.\n  NotLengthBetween = \"not-length-between\", // Check if the field value length is not between the provided values. The values must be an array of two numbers. The field value must be a string. Example: { \"field\": \"name\", \"operator\": \"not-between-length\", \"value\": [4, 8] } will check if the name field value length is not between 4 and 8.\n  Falsy = \"falsy\", // Check if the field value is falsy. The field value must be a string. Example: { \"field\": \"active\", \"operator\": \"falsy\" } will check if the active field value is falsy.\n  NotFalsy = \"not-falsy\", // Check if the field value is not falsy. The field value must be a string. Example: { \"field\": \"active\", \"operator\": \"not-falsy\" } will check if the active field value is not falsy.\n  Truthy = \"truthy\", // Check if the field value is truthy. The field value must be a string. Example: { \"field\": \"active\", \"operator\": \"truthy\" } will check if the active field value is truthy.\n  NotTruthy = \"not-truthy\", // Check if the field value is not truthy. The field value must be a string. Example: { \"field\": \"active\", \"operator\": \"not-truthy\" } will check if the active field value is not truthy.\n}\n"
  },
  {
    "path": "packages/core/src/examples/custom-operator.example.ts",
    "content": "/**\n * Example: Creating custom operators\n */\n\nimport { OperatorCategory, BaseOperatorStrategy } from \"@root/operators/base\";\nimport type { OperatorMetadata, OperatorContext } from \"@root/operators/base\";\nimport { registerCustomOperator } from \"@root/operators/factory\";\nimport { RuleEngine } from \"@root/services/rule-engine\";\n\n/**\n * Example 1: Custom IPv4 validation operator\n */\nclass IPv4Operator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: \"ipv4\" as any, // You would add this to the Operators enum\n    displayName: \"IPv4 Address\",\n    category: OperatorCategory.PATTERN,\n    description: \"Checks if the field value is a valid IPv4 address\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: true,\n    example: '{ field: \"ipAddress\", operator: \"ipv4\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n\n    const ipv4Regex =\n      /^(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})$/;\n    return ipv4Regex.test(fieldValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Example 2: Custom credit card validation operator\n */\nclass CreditCardOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata: OperatorMetadata = {\n    name: \"credit-card\" as any,\n    displayName: \"Credit Card\",\n    category: OperatorCategory.PATTERN,\n    description: \"Validates credit card numbers with optional type checking\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: false,\n    isNegatable: true,\n    example: '{ field: \"cardNumber\", operator: \"credit-card\", value: \"visa\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n\n    // Remove spaces and dashes\n    const cleaned = fieldValue.replace(/[\\s-]/g, \"\");\n\n    // Check if it's a valid credit card number using Luhn algorithm\n    if (!this.isValidLuhn(cleaned)) return false;\n\n    // If no specific type requested, just check Luhn validity\n    if (!constraintValue) return true;\n\n    // Check specific card type\n    return this.matchesCardType(cleaned, constraintValue as string);\n  }\n\n  private isValidLuhn(cardNumber: string): boolean {\n    if (!/^\\d+$/.test(cardNumber)) return false;\n\n    let sum = 0;\n    let isEven = false;\n\n    for (let i = cardNumber.length - 1; i >= 0; i--) {\n      let digit = Number.parseInt(cardNumber[i]!, 10);\n\n      if (isEven) {\n        digit *= 2;\n        if (digit > 9) {\n          digit -= 9;\n        }\n      }\n\n      sum += digit;\n      isEven = !isEven;\n    }\n\n    return sum % 10 === 0;\n  }\n\n  private matchesCardType(cardNumber: string, type: string): boolean {\n    const patterns: Record<string, RegExp> = {\n      visa: /^4\\d{12}(?:\\d{3})?$/,\n      mastercard: /^5[1-5]\\d{14}$/,\n      amex: /^3[47]\\d{13}$/,\n      discover: /^6(?:011|5\\d{2})\\d{12}$/,\n    };\n\n    const pattern = patterns[type.toLowerCase()];\n    return pattern ? pattern.test(cardNumber) : false;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return (\n      typeof value === \"string\" &&\n      [\"visa\", \"mastercard\", \"amex\", \"discover\"].includes(value.toLowerCase())\n    );\n  }\n}\n\n/**\n * Example 3: Custom range overlap operator\n */\nclass RangeOverlapOperator extends BaseOperatorStrategy<\n  [number, number],\n  [number, number]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: \"range-overlap\" as any,\n    displayName: \"Range Overlap\",\n    category: OperatorCategory.COMPARISON,\n    description: \"Checks if two numeric ranges overlap\",\n    acceptedFieldTypes: [\"array\"],\n    expectedValueType: \"range\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"availability\", operator: \"range-overlap\", value: [9, 17] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (!this.isValidRange(fieldValue) || !this.isValidRange(constraintValue)) {\n      return false;\n    }\n\n    const [fieldStart, fieldEnd] = fieldValue as [number, number];\n    const [constraintStart, constraintEnd] = constraintValue as [\n      number,\n      number,\n    ];\n\n    // Ranges overlap if one starts before the other ends\n    return fieldStart <= constraintEnd && constraintStart <= fieldEnd;\n  }\n\n  private isValidRange(value: unknown): value is [number, number] {\n    return (\n      Array.isArray(value) &&\n      value.length === 2 &&\n      typeof value[0] === \"number\" &&\n      typeof value[1] === \"number\" &&\n      value[0] <= value[1]\n    );\n  }\n\n  isValidFieldType(value: unknown): value is [number, number] {\n    return this.isValidRange(value);\n  }\n\n  isValidConstraintType(value: unknown): value is [number, number] {\n    return this.isValidRange(value);\n  }\n\n  override validate(\n    context: OperatorContext,\n  ): ReturnType<BaseOperatorStrategy[\"validate\"]> {\n    const baseValidation = super.validate(context);\n    if (!baseValidation.isValid) return baseValidation;\n\n    if (!this.isValidRange(context.fieldValue)) {\n      return {\n        isValid: false,\n        error:\n          \"Field value must be a valid range [start, end] where start <= end\",\n      };\n    }\n\n    if (!this.isValidRange(context.constraintValue)) {\n      return {\n        isValid: false,\n        error:\n          \"Constraint value must be a valid range [start, end] where start <= end\",\n      };\n    }\n\n    return baseValidation;\n  }\n}\n\n/**\n * Example 4: Custom business hours operator\n */\nclass BusinessHoursOperator extends BaseOperatorStrategy<Date, void> {\n  readonly metadata: OperatorMetadata = {\n    name: \"business-hours\" as any,\n    displayName: \"Business Hours\",\n    category: OperatorCategory.DATE_TIME,\n    description:\n      \"Checks if a datetime is within business hours (Mon-Fri 9AM-5PM)\",\n    acceptedFieldTypes: [\"date\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: true,\n    example: '{ field: \"requestTime\", operator: \"business-hours\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    let date: Date;\n    if (fieldValue instanceof Date) {\n      date = fieldValue;\n    } else if (\n      typeof fieldValue === \"string\" ||\n      typeof fieldValue === \"number\"\n    ) {\n      date = new Date(fieldValue);\n      if (Number.isNaN(date.getTime())) return false;\n    } else {\n      return false;\n    }\n\n    const dayOfWeek = date.getDay();\n    const hour = date.getHours();\n\n    // Monday-Friday (1-5)\n    if (dayOfWeek === 0 || dayOfWeek === 6) return false;\n\n    // 9 AM - 5 PM\n    return hour >= 9 && hour < 17;\n  }\n\n  isValidFieldType(value: unknown): value is Date {\n    return (\n      value instanceof Date ||\n      (typeof value === \"string\" && !Number.isNaN(Date.parse(value))) ||\n      (typeof value === \"number\" && !Number.isNaN(new Date(value).getTime()))\n    );\n  }\n}\n\n/**\n * Example usage\n */\nexport async function customOperatorExample() {\n  // Register custom operators\n  registerCustomOperator(IPv4Operator);\n  registerCustomOperator(CreditCardOperator);\n  registerCustomOperator(RangeOverlapOperator);\n  registerCustomOperator(BusinessHoursOperator);\n\n  // Example 1: IPv4 validation\n  const ipRule = {\n    conditions: {\n      and: [{ field: \"serverIp\", operator: \"ipv4\" as any }],\n    },\n  };\n\n  const ipResult = await RuleEngine.evaluate(ipRule, {\n    serverIp: \"192.168.1.1\",\n  });\n  console.log(\"IPv4 valid:\", ipResult.isPassed); // true\n\n  // Example 2: Credit card validation\n  const ccRule = {\n    conditions: {\n      and: [\n        { field: \"cardNumber\", operator: \"credit-card\" as any, value: \"visa\" },\n      ],\n    },\n  };\n\n  const ccResult = await RuleEngine.evaluate(ccRule, {\n    cardNumber: \"4111 1111 1111 1111\", // Test Visa number\n  });\n  console.log(\"Credit card valid:\", ccResult.isPassed); // true\n\n  // Example 3: Range overlap\n  const scheduleRule = {\n    conditions: {\n      and: [\n        {\n          field: \"meetingTime\",\n          operator: \"range-overlap\" as any,\n          value: [14, 16], // 2 PM - 4 PM\n        },\n      ],\n    },\n  };\n\n  const scheduleResult = await RuleEngine.evaluate(scheduleRule, {\n    meetingTime: [15, 17], // 3 PM - 5 PM (overlaps)\n  });\n  console.log(\"Schedule overlap:\", scheduleResult.isPassed); // true\n\n  // Example 4: Business hours check\n  const businessRule = {\n    conditions: {\n      and: [{ field: \"createdAt\", operator: \"business-hours\" as any }],\n    },\n  };\n\n  const businessResult = await RuleEngine.evaluate(businessRule, {\n    createdAt: new Date(\"2025-01-15T10:30:00\"), // Monday 10:30 AM\n  });\n  console.log(\"Within business hours:\", businessResult.isPassed); // true\n}\n\n/**\n * Example: Creating a custom operator factory\n */\nexport function createRegexOperator(\n  name: string,\n  pattern: RegExp,\n  description: string,\n) {\n  return class extends BaseOperatorStrategy<string, void> {\n    readonly metadata: OperatorMetadata = {\n      name: name as any,\n      displayName: name,\n      category: OperatorCategory.PATTERN,\n      description,\n      acceptedFieldTypes: [\"string\"],\n      expectedValueType: \"void\",\n      requiresValue: false,\n      isNegatable: true,\n      example: `{ field: \"value\", operator: \"${name}\" }`,\n    };\n\n    evaluate(context: OperatorContext): boolean {\n      const { fieldValue } = context;\n      return typeof fieldValue === \"string\" && pattern.test(fieldValue);\n    }\n\n    isValidFieldType(value: unknown): value is string {\n      return typeof value === \"string\";\n    }\n  };\n}\n\n// Usage\nconst PhoneOperator = createRegexOperator(\n  \"phone\",\n  /^\\+?[1-9]\\d{1,14}$/,\n  \"Validates international phone numbers (E.164 format)\",\n);\n\nregisterCustomOperator(PhoneOperator);\n"
  },
  {
    "path": "packages/core/src/index.ts",
    "content": "// Enums\nexport * from \"@root/enums\";\n// Explicit re-export for better TypeScript support\nexport { ConditionTypes, Operators } from \"@root/enums\";\n// Legacy operators (for backward compatibility)\nexport * from \"@root/operators\";\n// Operator System Base (must come before implementations)\nexport {\n  BaseOperatorStrategy,\n  type FieldType,\n  OperatorCategory,\n  type OperatorConstructor,\n  type OperatorContext,\n  type OperatorFactory,\n  type OperatorMetadata,\n  type OperatorStrategy,\n  type ValidationResult as OperatorValidationResult,\n  type ValueType,\n} from \"@root/operators/base\";\n// Operator System\nexport {\n  initializeOperators,\n  registerBuiltInOperators,\n  registerCustomOperator,\n  registerCustomOperators,\n} from \"@root/operators/factory\";\n// Operator implementations\nexport {\n  // Comparison operators\n  BetweenOperator,\n  // String operators\n  ContainsStringOperator,\n  EndsWithOperator,\n  EqualsOperator,\n  GreaterThanOperator,\n  GreaterThanOrEqualsOperator,\n  InOperator,\n  LengthBetweenOperator,\n  LessThanOperator,\n  LessThanOrEqualsOperator,\n  LikeOperator,\n  MaxLengthOperator,\n  MinLengthOperator,\n  NotBetweenOperator,\n  NotEqualsOperator,\n  NotInOperator,\n  NotLikeOperator,\n  StartsWithOperator,\n  StringLengthOperator,\n} from \"@root/operators/implementations\";\n\nexport { OperatorRegistry, operatorRegistry } from \"@root/operators/registry\";\n\n// Services\nexport { ObjectDiscovery } from \"@root/services\";\nexport { Evaluator } from \"@root/services/evaluator\";\n\nexport { Introspector } from \"@root/services/introspector\";\nexport type { EnhancedIntrospectionResult } from \"@root/services/introspector\";\nexport { RuleEngine } from \"@root/services/rule-engine\";\nexport type { RuleEngineConfig } from \"@root/services/rule-engine\";\n// Types (excluding ValidationResult to avoid conflict)\nexport {\n  type Condition,\n  type ConditionType,\n  type Constraint,\n  type Criteria,\n  type CriteriaObject,\n  type CriteriaRange,\n  type EngineResult,\n  type EvaluationResult,\n  type IntrospectionResult,\n  type IntrospectionStep,\n  type OperatorsType,\n  type RuleType,\n} from \"@root/types\";\n// Utils\nexport * from \"@root/utils\";\n"
  },
  {
    "path": "packages/core/src/operators/base.ts",
    "content": "import type { OperatorsType } from \"@root/types\";\n\n/**\n * Type representing the expected field types for operators\n */\nexport type FieldType =\n  | \"string\"\n  | \"number\"\n  | \"boolean\"\n  | \"date\"\n  | \"array\"\n  | \"object\"\n  | \"any\"\n  | \"time\";\n\n/**\n * Type representing the expected value types for operators\n */\nexport type ValueType = FieldType | \"regex\" | \"range\" | \"void\";\n\n/**\n * Metadata for an operator\n */\nexport interface OperatorMetadata {\n  /**\n   * Unique name of the operator\n   */\n  name: OperatorsType;\n\n  /**\n   * Human-readable display name\n   */\n  displayName: string;\n\n  /**\n   * Category for grouping operators\n   */\n  category: OperatorCategory;\n\n  /**\n   * Description of what the operator does\n   */\n  description: string;\n\n  /**\n   * Accepted field types\n   */\n  acceptedFieldTypes: FieldType[];\n\n  /**\n   * Expected value type\n   */\n  expectedValueType: ValueType;\n\n  /**\n   * Whether the operator requires a value\n   */\n  requiresValue: boolean;\n\n  /**\n   * Whether the operator is negatable (has a NOT version)\n   */\n  isNegatable?: boolean;\n\n  /**\n   * Example usage\n   */\n  example?: string;\n}\n\n/**\n * Operator categories for organization\n */\nexport enum OperatorCategory {\n  COMPARISON = \"comparison\",\n  STRING = \"string\",\n  NUMERIC = \"numeric\",\n  ARRAY = \"array\",\n  DATE_TIME = \"date_time\",\n  TYPE = \"type\",\n  EXISTENCE = \"existence\",\n  BOOLEAN = \"boolean\",\n  PATTERN = \"pattern\",\n  PERSIAN = \"persian\",\n}\n\n/**\n * Context passed to operators during evaluation\n */\nexport interface OperatorContext {\n  /**\n   * The field value being evaluated\n   */\n  fieldValue: any;\n\n  /**\n   * The constraint value to compare against\n   */\n  constraintValue?: any;\n\n  /**\n   * The full criteria object for self-referencing\n   */\n  criteria?: Record<string, any>;\n\n  /**\n   * The field path that was resolved\n   */\n  fieldPath?: string;\n}\n\n/**\n * Result of operator validation\n */\nexport interface ValidationResult {\n  isValid: boolean;\n  error?: string;\n  warnings?: string[];\n}\n\n/**\n * Base interface for all operator strategies\n */\nexport interface OperatorStrategy<TField = any, TValue = any> {\n  /**\n   * Metadata about the operator\n   */\n  readonly metadata: OperatorMetadata;\n\n  /**\n   * Validates the input values before evaluation\n   * @param context The operator context\n   * @returns Validation result\n   */\n  validate(context: OperatorContext): ValidationResult;\n\n  /**\n   * Evaluates the operator logic\n   * @param context The operator context\n   * @returns Boolean result of the evaluation\n   */\n  evaluate(context: OperatorContext): boolean;\n\n  /**\n   * Type guard for field value\n   * @param value The value to check\n   * @returns Type predicate\n   */\n  isValidFieldType?(value: unknown): value is TField;\n\n  /**\n   * Type guard for constraint value\n   * @param value The value to check\n   * @returns Type predicate\n   */\n  isValidConstraintType?(value: unknown): value is TValue;\n\n  /**\n   * Gets the negated version of this operator\n   * @returns The negated operator strategy or null if not negatable\n   */\n  getNegated?(): OperatorStrategy<TField, TValue> | null;\n\n  /**\n   * Formats error messages with context\n   * @param template Message template with placeholders\n   * @param context The operator context\n   * @returns Formatted message\n   */\n  formatMessage?(template: string, context: OperatorContext): string;\n}\n\n/**\n * Base abstract class for operator strategies\n */\nexport abstract class BaseOperatorStrategy<TField = any, TValue = any>\n  implements OperatorStrategy<TField, TValue>\n{\n  abstract readonly metadata: OperatorMetadata;\n\n  /**\n   * Default validation implementation\n   */\n  validate(context: OperatorContext): ValidationResult {\n    const { fieldValue, constraintValue } = context;\n\n    // Check if value is required but not provided\n    if (this.metadata.requiresValue && constraintValue === undefined) {\n      return {\n        isValid: false,\n        error: `Operator \"${this.metadata.displayName}\" requires a value`,\n      };\n    }\n\n    // Validate field type if type guard is implemented\n    if (\n      \"isValidFieldType\" in this &&\n      typeof this.isValidFieldType === \"function\" &&\n      !this.isValidFieldType(fieldValue)\n    ) {\n      return {\n        isValid: false,\n        error: `Invalid field type for operator \"${this.metadata.displayName}\". Expected one of: ${this.metadata.acceptedFieldTypes.join(\", \")}`,\n      };\n    }\n\n    // Validate constraint type if type guard is implemented\n    if (\n      \"isValidConstraintType\" in this &&\n      typeof this.isValidConstraintType === \"function\" &&\n      constraintValue !== undefined\n    ) {\n      if (!this.isValidConstraintType(constraintValue)) {\n        return {\n          isValid: false,\n          error: `Invalid value type for operator \"${this.metadata.displayName}\". Expected: ${this.metadata.expectedValueType}`,\n        };\n      }\n    }\n\n    return { isValid: true };\n  }\n\n  abstract evaluate(context: OperatorContext): boolean;\n\n  /**\n   * Default message formatter\n   */\n  formatMessage(template: string, context: OperatorContext): string {\n    return template\n      .replace(\"{{field}}\", context.fieldPath || \"field\")\n      .replace(\"{{value}}\", JSON.stringify(context.constraintValue))\n      .replace(\"{{fieldValue}}\", JSON.stringify(context.fieldValue));\n  }\n}\n\n/**\n * Factory function type for creating operator instances\n */\nexport type OperatorFactory = () => OperatorStrategy;\n\n/**\n * Type for operator constructor\n */\nexport type OperatorConstructor = new () => OperatorStrategy;\n"
  },
  {
    "path": "packages/core/src/operators/factory.ts",
    "content": "import { operatorRegistry } from \"./registry\";\nimport type { OperatorFactory, OperatorConstructor } from \"./base\";\n\n// Import all operator implementations\nimport {\n  ZeroOperator,\n  UUIDOperator,\n  UrlOperator,\n  UpperCaseOperator,\n  TruthyOperator,\n  TimeNotEqualsOperator,\n  TimeNotBetweenOperator,\n  TimeEqualsOperator,\n  TimeBetweenOperator,\n  TimeBeforeOrEqualsOperator,\n  TimeBeforeOperator,\n  TimeAfterOrEqualsOperator,\n  TimeAfterOperator,\n  StringOperator,\n  StringLengthOperator,\n  StartsWithOperator,\n  SelfNotContainsAnyOperator,\n  SelfNotContainsAllOperator,\n  SelfContainsNoneOperator,\n  SelfContainsAnyOperator,\n  SelfContainsAllOperator,\n  PositiveOperator,\n  PersianAlphaOperator,\n  PersianAlphaNumericOperator,\n  ObjectOperator,\n  NumericOperator,\n  NumberOperator,\n  NumberBetweenOperator,\n  NullOrWhiteSpaceOperator,\n  NullOrUndefinedOperator,\n  NotZeroOperator,\n  NotUUIDOperator,\n  NotUrlOperator,\n  NotUpperCaseOperator,\n  NotTruthyOperator,\n  NotStringOperator,\n  NotStringLengthOperator,\n  NotPositiveOperator,\n  NotPersianAlphaOperator,\n  NotPersianAlphaNumericOperator,\n  // Type\n  NotObjectOperator,\n  NotNumericOperator,\n  NotNumberOperator,\n  NotNumberBetweenOperator,\n  NotNullOrWhiteSpaceOperator,\n  NotNullOrUndefinedOperator,\n  NotNegativeOperator,\n  NotMatchesOperator,\n  NotLowerCaseOperator,\n  NotLikeOperator,\n  NotLengthBetweenOperator,\n  NotIntegerOperator,\n  NotInOperator,\n  NotFloatOperator,\n  NotFalsyOperator,\n  NotExistsOperator,\n  NotEqualsOperator,\n  NotEmptyOperator,\n  NotEmailOperator,\n  NotDateOperator,\n  NotContainsOperator,\n  NotContainsAnyOperator,\n  NotContainsAllOperator,\n  NotBooleanStringOperator,\n  NotBooleanOperator,\n  NotBooleanNumberStringOperator,\n  NotBooleanNumberOperator,\n  NotBetweenOperator,\n  NotArrayOperator,\n  NotAlphaOperator,\n  NotAlphaNumericOperator,\n  NegativeOperator,\n  MinOperator,\n  MinLengthOperator,\n  MaxOperator,\n  MaxLengthOperator,\n  MatchesOperator,\n  LowerCaseOperator,\n  LikeOperator,\n  LessThanOrEqualsOperator,\n  LessThanOperator,\n  LengthBetweenOperator,\n  IntegerOperator,\n  InOperator,\n  GreaterThanOrEqualsOperator,\n  GreaterThanOperator,\n  // Numeric\n  FloatOperator,\n  FalsyOperator,\n  ExistsOperator,\n  EqualsOperator,\n  EndsWithOperator,\n  // Existence\n  EmptyOperator,\n  EmailOperator,\n  DateOperator,\n  DateNotEqualsToNowOperator,\n  DateNotEqualsOperator,\n  DateNotBetweenOperator,\n  DateEqualsToNowOperator,\n  DateEqualsOperator,\n  DateBetweenOperator,\n  DateBeforeOrEqualsOperator,\n  DateBeforeOperator,\n  DateBeforeNowOrEqualsOperator,\n  DateBeforeNowOperator,\n  DateAfterOrEqualsOperator,\n  DateAfterOperator,\n  DateAfterNowOrEqualsOperator,\n  // Date/Time\n  DateAfterNowOperator,\n  // String\n  ContainsStringOperator,\n  ContainsOperator,\n  ContainsAnyOperator,\n  ContainsAllOperator,\n  BooleanStringOperator,\n  BooleanOperator,\n  BooleanNumberStringOperator,\n  // Boolean\n  BooleanNumberOperator,\n  // Comparison\n  BetweenOperator,\n  // Array\n  ArrayOperator,\n  AlphaOperator,\n  // Pattern\n  AlphaNumericOperator,\n} from \"./implementations\";\n\n/**\n * List of all built-in operator classes\n */\nconst BUILT_IN_OPERATORS: Array<OperatorConstructor> = [\n  // Array operators\n  ArrayOperator,\n  NotArrayOperator,\n  ContainsOperator,\n  NotContainsOperator,\n  ContainsAnyOperator,\n  NotContainsAnyOperator,\n  ContainsAllOperator,\n  NotContainsAllOperator,\n  SelfContainsAnyOperator,\n  SelfNotContainsAnyOperator,\n  SelfContainsAllOperator,\n  SelfNotContainsAllOperator,\n  SelfContainsNoneOperator,\n  // Boolean operators\n  BooleanOperator,\n  NotBooleanOperator,\n  BooleanStringOperator,\n  NotBooleanStringOperator,\n  BooleanNumberOperator,\n  NotBooleanNumberOperator,\n  BooleanNumberStringOperator,\n  NotBooleanNumberStringOperator,\n  TruthyOperator,\n  NotTruthyOperator,\n  FalsyOperator,\n  NotFalsyOperator,\n  // Comparison operators\n  EqualsOperator,\n  NotEqualsOperator,\n  GreaterThanOperator,\n  GreaterThanOrEqualsOperator,\n  LessThanOperator,\n  LessThanOrEqualsOperator,\n  InOperator,\n  NotInOperator,\n  BetweenOperator,\n  NotBetweenOperator,\n  // Date/Time operators\n  DateAfterOperator,\n  DateAfterNowOperator,\n  DateAfterNowOrEqualsOperator,\n  DateBeforeOperator,\n  DateBeforeNowOperator,\n  DateBeforeNowOrEqualsOperator,\n  DateEqualsOperator,\n  DateEqualsToNowOperator,\n  DateNotEqualsOperator,\n  DateNotEqualsToNowOperator,\n  DateAfterOrEqualsOperator,\n  DateBeforeOrEqualsOperator,\n  DateBetweenOperator,\n  DateNotBetweenOperator,\n  TimeAfterOperator,\n  TimeAfterOrEqualsOperator,\n  TimeBeforeOperator,\n  TimeBeforeOrEqualsOperator,\n  TimeEqualsOperator,\n  TimeNotEqualsOperator,\n  TimeBetweenOperator,\n  TimeNotBetweenOperator,\n  DateOperator,\n  NotDateOperator,\n  // Existence operators\n  ExistsOperator,\n  NotExistsOperator,\n  NullOrUndefinedOperator,\n  NotNullOrUndefinedOperator,\n  EmptyOperator,\n  NotEmptyOperator,\n  NullOrWhiteSpaceOperator,\n  NotNullOrWhiteSpaceOperator,\n  // Numeric operators\n  NumericOperator,\n  NotNumericOperator,\n  NumberOperator,\n  NotNumberOperator,\n  IntegerOperator,\n  NotIntegerOperator,\n  FloatOperator,\n  NotFloatOperator,\n  PositiveOperator,\n  NotPositiveOperator,\n  NegativeOperator,\n  NotNegativeOperator,\n  ZeroOperator,\n  NotZeroOperator,\n  MinOperator,\n  MaxOperator,\n  NumberBetweenOperator,\n  NotNumberBetweenOperator,\n  // Pattern operators\n  EmailOperator,\n  NotEmailOperator,\n  UrlOperator,\n  NotUrlOperator,\n  UUIDOperator,\n  NotUUIDOperator,\n  AlphaOperator,\n  NotAlphaOperator,\n  AlphaNumericOperator,\n  NotAlphaNumericOperator,\n  PersianAlphaOperator,\n  NotPersianAlphaOperator,\n  PersianAlphaNumericOperator,\n  NotPersianAlphaNumericOperator,\n  LowerCaseOperator,\n  NotLowerCaseOperator,\n  UpperCaseOperator,\n  NotUpperCaseOperator,\n  MatchesOperator,\n  NotMatchesOperator,\n  // String operators\n  LikeOperator,\n  NotLikeOperator,\n  StartsWithOperator,\n  EndsWithOperator,\n  ContainsStringOperator,\n  StringLengthOperator,\n  NotStringLengthOperator,\n  MinLengthOperator,\n  MaxLengthOperator,\n  LengthBetweenOperator,\n  NotLengthBetweenOperator,\n  // Type operators\n  StringOperator,\n  NotStringOperator,\n  ObjectOperator,\n  NotObjectOperator,\n];\n\n/**\n * Register all built-in operators\n * @param override Whether to override existing operators\n */\nexport function registerBuiltInOperators(override = false): void {\n  // Only register if not already initialized\n  if (!operatorRegistry.isInitialized() || override) {\n    operatorRegistry.registerMany(BUILT_IN_OPERATORS, override);\n    operatorRegistry.markInitialized();\n  }\n}\n\n/**\n * Register a custom operator\n * @param operator The operator class or factory\n * @param override Whether to override existing operator\n */\nexport function registerCustomOperator(\n  operator: OperatorConstructor | OperatorFactory,\n  override = false,\n): void {\n  operatorRegistry.register(operator, override);\n}\n\n/**\n * Register multiple custom operators\n * @param operators Array of operator classes or factories\n * @param override Whether to override existing operators\n */\nexport function registerCustomOperators(\n  operators: Array<OperatorConstructor | OperatorFactory>,\n  override = false,\n): void {\n  operatorRegistry.registerMany(operators, override);\n}\n\n/**\n * Initialize the operator system with built-in operators\n * This should be called once at application startup\n */\nexport function initializeOperators(): void {\n  // Only initialize if not already done\n  if (!operatorRegistry.isInitialized()) {\n    registerBuiltInOperators();\n  }\n}\n\n// Export registry instance for direct access if needed\nexport { operatorRegistry } from \"./registry\";\n"
  },
  {
    "path": "packages/core/src/operators/implementations/array.ts",
    "content": "import { Operators } from \"@root/enums\";\nimport { OperatorCategory, BaseOperatorStrategy } from \"../base\";\nimport type { OperatorMetadata, OperatorContext } from \"../base\";\n\n/**\n * Contains operator - checks if array contains value\n */\nexport class ContainsOperator extends BaseOperatorStrategy<any[], any> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Contains,\n    displayName: \"Contains\",\n    category: OperatorCategory.ARRAY,\n    description: \"Checks if the array contains the specified value\",\n    acceptedFieldTypes: [\"array\"],\n    expectedValueType: \"any\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"tags\", operator: \"contains\", value: \"featured\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (!Array.isArray(fieldValue)) return false;\n\n    return fieldValue.includes(constraintValue);\n  }\n\n  isValidFieldType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Not Contains operator\n */\nexport class NotContainsOperator extends BaseOperatorStrategy<any[], any> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotContains,\n    displayName: \"Not Contains\",\n    category: OperatorCategory.ARRAY,\n    description: \"Checks if the array does not contain the specified value\",\n    acceptedFieldTypes: [\"array\"],\n    expectedValueType: \"any\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"tags\", operator: \"not-contains\", value: \"draft\" }',\n  };\n\n  private containsOperator = new ContainsOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.containsOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Contains Any operator - checks if array contains any of the values\n */\nexport class ContainsAnyOperator extends BaseOperatorStrategy<any[], any[]> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.ContainsAny,\n    displayName: \"Contains Any\",\n    category: OperatorCategory.ARRAY,\n    description: \"Checks if the array contains any of the specified values\",\n    acceptedFieldTypes: [\"array\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"roles\", operator: \"contains-any\", value: [\"admin\", \"moderator\"] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (!Array.isArray(fieldValue) || !Array.isArray(constraintValue))\n      return false;\n\n    return fieldValue.some((item) => constraintValue.includes(item));\n  }\n\n  isValidFieldType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n\n  isValidConstraintType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Not Contains Any operator\n */\nexport class NotContainsAnyOperator extends BaseOperatorStrategy<any[], any[]> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotContainsAny,\n    displayName: \"Not Contains Any\",\n    category: OperatorCategory.ARRAY,\n    description:\n      \"Checks if the array does not contain any of the specified values\",\n    acceptedFieldTypes: [\"array\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"roles\", operator: \"not-contains-any\", value: [\"banned\", \"suspended\"] }',\n  };\n\n  private containsAnyOperator = new ContainsAnyOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.containsAnyOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n\n  isValidConstraintType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Contains All operator - checks if array contains all values\n */\nexport class ContainsAllOperator extends BaseOperatorStrategy<any[], any[]> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.ContainsAll,\n    displayName: \"Contains All\",\n    category: OperatorCategory.ARRAY,\n    description: \"Checks if the array contains all of the specified values\",\n    acceptedFieldTypes: [\"array\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"permissions\", operator: \"contains-all\", value: [\"read\", \"write\"] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (!Array.isArray(fieldValue) || !Array.isArray(constraintValue))\n      return false;\n\n    return constraintValue.every((value) => fieldValue.includes(value));\n  }\n\n  isValidFieldType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n\n  isValidConstraintType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Not Contains All operator\n */\nexport class NotContainsAllOperator extends BaseOperatorStrategy<any[], any[]> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotContainsAll,\n    displayName: \"Not Contains All\",\n    category: OperatorCategory.ARRAY,\n    description:\n      \"Checks if the array does not contain all of the specified values\",\n    acceptedFieldTypes: [\"array\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"features\", operator: \"not-contains-all\", value: [\"premium\", \"enterprise\"] }',\n  };\n\n  private containsAllOperator = new ContainsAllOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.containsAllOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n\n  isValidConstraintType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Array Length operator - checks array length\n */\nexport class ArrayLengthOperator extends BaseOperatorStrategy<any[], number> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.ArrayLength,\n    displayName: \"Array Length\",\n    category: OperatorCategory.ARRAY,\n    description: \"Checks if the array length equals the specified value\",\n    acceptedFieldTypes: [\"array\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"items\", operator: \"array-length\", value: 5 }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (!Array.isArray(fieldValue) || typeof constraintValue !== \"number\")\n      return false;\n\n    return fieldValue.length === constraintValue;\n  }\n\n  isValidFieldType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n\n  isValidConstraintType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Array Min Length operator\n */\nexport class ArrayMinLengthOperator extends BaseOperatorStrategy<\n  any[],\n  number\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.ArrayMinLength,\n    displayName: \"Array Minimum Length\",\n    category: OperatorCategory.ARRAY,\n    description: \"Checks if the array length is at least the specified value\",\n    acceptedFieldTypes: [\"array\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"attendees\", operator: \"array-min-length\", value: 2 }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (!Array.isArray(fieldValue) || typeof constraintValue !== \"number\")\n      return false;\n\n    return fieldValue.length >= constraintValue;\n  }\n\n  isValidFieldType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n\n  isValidConstraintType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Array Max Length operator\n */\nexport class ArrayMaxLengthOperator extends BaseOperatorStrategy<\n  any[],\n  number\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.ArrayMaxLength,\n    displayName: \"Array Maximum Length\",\n    category: OperatorCategory.ARRAY,\n    description: \"Checks if the array length is at most the specified value\",\n    acceptedFieldTypes: [\"array\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"tags\", operator: \"array-max-length\", value: 10 }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (!Array.isArray(fieldValue) || typeof constraintValue !== \"number\")\n      return false;\n\n    return fieldValue.length <= constraintValue;\n  }\n\n  isValidFieldType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n\n  isValidConstraintType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Self Contains Any operator - checks if string field contains any values from constraint array\n */\nexport class SelfContainsAnyOperator extends BaseOperatorStrategy<\n  string,\n  any[]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.SelfContainsAny,\n    displayName: \"Self Contains Any\",\n    category: OperatorCategory.STRING,\n    description:\n      \"Checks if the string field contains any of the values in the constraint array\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"password\", operator: \"self-contains-any\", value: [\"admin\", \"user\"] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || !Array.isArray(constraintValue))\n      return false;\n\n    return constraintValue.some((value) => fieldValue.includes(String(value)));\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Self Not Contains Any operator\n */\nexport class SelfNotContainsAnyOperator extends BaseOperatorStrategy<\n  string,\n  any[]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.SelfNotContainsAny,\n    displayName: \"Self Not Contains Any\",\n    category: OperatorCategory.STRING,\n    description:\n      \"Checks if the string field does not contain any of the values in the constraint array\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"password\", operator: \"self-not-contains-any\", value: [\"admin\", \"test\"] }',\n  };\n\n  private selfContainsAnyOperator = new SelfContainsAnyOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.selfContainsAnyOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Self Contains All operator\n */\nexport class SelfContainsAllOperator extends BaseOperatorStrategy<\n  string,\n  any[]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.SelfContainsAll,\n    displayName: \"Self Contains All\",\n    category: OperatorCategory.STRING,\n    description:\n      \"Checks if the string field contains all of the values in the constraint array\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"password\", operator: \"self-contains-all\", value: [\"pass\", \"word\"] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || !Array.isArray(constraintValue))\n      return false;\n\n    return constraintValue.every((value) => fieldValue.includes(String(value)));\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Self Not Contains All operator\n */\nexport class SelfNotContainsAllOperator extends BaseOperatorStrategy<\n  string,\n  any[]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.SelfNotContainsAll,\n    displayName: \"Self Not Contains All\",\n    category: OperatorCategory.STRING,\n    description:\n      \"Checks if the string field does not contain all of the values in the constraint array\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"password\", operator: \"self-not-contains-all\", value: [\"admin\", \"123\"] }',\n  };\n\n  private selfContainsAllOperator = new SelfContainsAllOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.selfContainsAllOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Self Contains None operator - alias for Self Not Contains Any\n * Checks that the string field contains none of the values in the array\n */\nexport class SelfContainsNoneOperator extends BaseOperatorStrategy<\n  string,\n  any[]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.SelfContainsNone,\n    displayName: \"Self Contains None\",\n    category: OperatorCategory.STRING,\n    description:\n      \"Checks if the string field contains none of the values in the constraint array\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: false,\n    example:\n      '{ field: \"password\", operator: \"self-not-contains-none\", value: [\"admin\", \"test\"] }',\n  };\n\n  // This is the same as SelfNotContainsAny\n  private selfNotContainsAnyOperator = new SelfNotContainsAnyOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return this.selfNotContainsAnyOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n"
  },
  {
    "path": "packages/core/src/operators/implementations/boolean.ts",
    "content": "import { Operators } from \"@root/enums\";\nimport { OperatorCategory, BaseOperatorStrategy } from \"../base\";\nimport type { OperatorMetadata, OperatorContext } from \"../base\";\nimport { isFalsyOperator } from \"@root/operators\";\n\n/**\n * Boolean operator - checks if value is boolean\n */\nexport class BooleanOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Boolean,\n    displayName: \"Is Boolean\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is a boolean\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"isActive\", operator: \"boolean\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return typeof fieldValue === \"boolean\";\n  }\n}\n\n/**\n * Not Boolean operator\n */\nexport class NotBooleanOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotBoolean,\n    displayName: \"Is Not Boolean\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not a boolean\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"status\", operator: \"not-boolean\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return typeof fieldValue !== \"boolean\";\n  }\n}\n\n/**\n * Boolean String operator - checks if string represents a boolean\n */\nexport class BooleanStringOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.BooleanString,\n    displayName: \"Is Boolean String\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is a boolean string (true/false)\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"enabled\", operator: \"boolean-string\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return (\n      typeof fieldValue === \"string\" &&\n      (fieldValue === \"true\" || fieldValue === \"false\")\n    );\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not Boolean String operator\n */\nexport class NotBooleanStringOperator extends BaseOperatorStrategy<\n  string,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotBooleanString,\n    displayName: \"Is Not Boolean String\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not a boolean string\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"value\", operator: \"not-boolean-string\" }',\n  };\n\n  private booleanStringOperator = new BooleanStringOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.booleanStringOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Boolean Number operator - checks if number represents a boolean (0 or 1)\n */\nexport class BooleanNumberOperator extends BaseOperatorStrategy<number, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.BooleanNumber,\n    displayName: \"Is Boolean Number\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is a boolean number (0 or 1)\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"flag\", operator: \"boolean-number\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return (\n      typeof fieldValue === \"number\" && (fieldValue === 0 || fieldValue === 1)\n    );\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Not Boolean Number operator\n */\nexport class NotBooleanNumberOperator extends BaseOperatorStrategy<\n  number,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotBooleanNumber,\n    displayName: \"Is Not Boolean Number\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not a boolean number\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"count\", operator: \"not-boolean-number\" }',\n  };\n\n  private booleanNumberOperator = new BooleanNumberOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.booleanNumberOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Boolean Number String operator - checks if string represents a boolean number\n */\nexport class BooleanNumberStringOperator extends BaseOperatorStrategy<\n  string,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.BooleanNumberString,\n    displayName: \"Is Boolean Number String\",\n    category: OperatorCategory.TYPE,\n    description:\n      \"Checks if the field value is a boolean number string (0 or 1)\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"active\", operator: \"boolean-number-string\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return (\n      typeof fieldValue === \"string\" &&\n      (fieldValue === \"0\" || fieldValue === \"1\")\n    );\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not Boolean Number String operator\n */\nexport class NotBooleanNumberStringOperator extends BaseOperatorStrategy<\n  string,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotBooleanNumberString,\n    displayName: \"Is Not Boolean Number String\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not a boolean number string\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"value\", operator: \"not-boolean-number-string\" }',\n  };\n\n  private booleanNumberStringOperator = new BooleanNumberStringOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.booleanNumberStringOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Truthy operator - checks if value is truthy\n */\nexport class TruthyOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Truthy,\n    displayName: \"Is Truthy\",\n    category: OperatorCategory.BOOLEAN,\n    description: \"Checks if the field value is truthy\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"hasPermission\", operator: \"truthy\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return !!fieldValue;\n  }\n}\n\n/**\n * Not Truthy operator\n */\nexport class NotTruthyOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotTruthy,\n    displayName: \"Is Not Truthy\",\n    category: OperatorCategory.BOOLEAN,\n    description: \"Checks if the field value is not truthy\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"disabled\", operator: \"not-truthy\" }',\n  };\n\n  private truthyOperator = new TruthyOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.truthyOperator.evaluate(context);\n  }\n}\n\n/**\n * Falsy operator - checks if value is falsy\n */\nexport class FalsyOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Falsy,\n    displayName: \"Is Falsy\",\n    category: OperatorCategory.BOOLEAN,\n    description: \"Checks if the field value is falsy\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"isDisabled\", operator: \"falsy\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return isFalsyOperator(fieldValue);\n  }\n}\n\n/**\n * Not Falsy operator\n */\nexport class NotFalsyOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotFalsy,\n    displayName: \"Is Not Falsy\",\n    category: OperatorCategory.BOOLEAN,\n    description: \"Checks if the field value is not falsy\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"isEnabled\", operator: \"not-falsy\" }',\n  };\n\n  private falsyOperator = new FalsyOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.falsyOperator.evaluate(context);\n  }\n}\n"
  },
  {
    "path": "packages/core/src/operators/implementations/comparison.ts",
    "content": "import { isObject } from \"@root/utils\";\nimport { Operators } from \"@root/enums\";\nimport { OperatorCategory, BaseOperatorStrategy } from \"../base\";\nimport type { OperatorMetadata, OperatorContext } from \"../base\";\n\n/**\n * Equals operator - checks if values are equal\n */\nexport class EqualsOperator extends BaseOperatorStrategy<any, any> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Equals,\n    displayName: \"Equals\",\n    category: OperatorCategory.COMPARISON,\n    description: \"Checks if the field value equals the constraint value\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"any\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"age\", operator: \"equals\", value: 25 }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (fieldValue === undefined || constraintValue === undefined) return false;\n    if (fieldValue === null || constraintValue === null)\n      return fieldValue === constraintValue;\n    if (typeof fieldValue !== typeof constraintValue) return false;\n\n    if (fieldValue instanceof Date && constraintValue instanceof Date) {\n      return fieldValue.getTime() === constraintValue.getTime();\n    }\n\n    if (\n      (isObject(fieldValue) && isObject(constraintValue)) ||\n      (Array.isArray(fieldValue) && Array.isArray(constraintValue))\n    ) {\n      return JSON.stringify(fieldValue) === JSON.stringify(constraintValue);\n    }\n\n    return fieldValue === constraintValue;\n  }\n}\n\n/**\n * Not Equals operator\n */\nexport class NotEqualsOperator extends BaseOperatorStrategy<any, any> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotEquals,\n    displayName: \"Not Equals\",\n    category: OperatorCategory.COMPARISON,\n    description:\n      \"Checks if the field value does not equal the constraint value\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"any\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"status\", operator: \"not-equals\", value: \"inactive\" }',\n  };\n\n  private equalsOperator = new EqualsOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.equalsOperator.evaluate(context);\n  }\n}\n\n/**\n * Greater Than operator\n */\nexport class GreaterThanOperator extends BaseOperatorStrategy<\n  number | string | Date,\n  number | string | Date\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.GreaterThan,\n    displayName: \"Greater Than\",\n    category: OperatorCategory.COMPARISON,\n    description:\n      \"Checks if the field value is greater than the constraint value\",\n    acceptedFieldTypes: [\"number\", \"string\", \"date\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"age\", operator: \"greater-than\", value: 18 }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (fieldValue === undefined || constraintValue === undefined) return false;\n    if (fieldValue === null || constraintValue === null) return false;\n    if (typeof fieldValue !== typeof constraintValue) return false;\n\n    return fieldValue > constraintValue;\n  }\n\n  isValidFieldType(value: unknown): value is number | string | Date {\n    return (\n      typeof value === \"number\" ||\n      typeof value === \"string\" ||\n      value instanceof Date\n    );\n  }\n\n  isValidConstraintType(value: unknown): value is number | string | Date {\n    return this.isValidFieldType(value);\n  }\n}\n\n/**\n * Greater Than or Equals operator\n */\nexport class GreaterThanOrEqualsOperator extends BaseOperatorStrategy<\n  number | string | Date,\n  number | string | Date\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.GreaterThanOrEquals,\n    displayName: \"Greater Than or Equals\",\n    category: OperatorCategory.COMPARISON,\n    description:\n      \"Checks if the field value is greater than or equal to the constraint value\",\n    acceptedFieldTypes: [\"number\", \"string\", \"date\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"score\", operator: \"greater-than-or-equals\", value: 60 }',\n  };\n\n  private equalsOperator = new EqualsOperator();\n  private greaterThanOperator = new GreaterThanOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return (\n      this.equalsOperator.evaluate(context) ||\n      this.greaterThanOperator.evaluate(context)\n    );\n  }\n\n  isValidFieldType(value: unknown): value is number | string | Date {\n    return this.greaterThanOperator.isValidFieldType!(value);\n  }\n\n  isValidConstraintType(value: unknown): value is number | string | Date {\n    return this.greaterThanOperator.isValidConstraintType!(value);\n  }\n}\n\n/**\n * Less Than operator\n */\nexport class LessThanOperator extends BaseOperatorStrategy<\n  number | string | Date,\n  number | string | Date\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.LessThan,\n    displayName: \"Less Than\",\n    category: OperatorCategory.COMPARISON,\n    description: \"Checks if the field value is less than the constraint value\",\n    acceptedFieldTypes: [\"number\", \"string\", \"date\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"price\", operator: \"less-than\", value: 100 }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (fieldValue === undefined || constraintValue === undefined) return false;\n    if (fieldValue === null || constraintValue === null) return false;\n    if (typeof fieldValue !== typeof constraintValue) return false;\n\n    return fieldValue < constraintValue;\n  }\n\n  isValidFieldType(value: unknown): value is number | string | Date {\n    return (\n      typeof value === \"number\" ||\n      typeof value === \"string\" ||\n      value instanceof Date\n    );\n  }\n\n  isValidConstraintType(value: unknown): value is number | string | Date {\n    return this.isValidFieldType(value);\n  }\n}\n\n/**\n * Less Than or Equals operator\n */\nexport class LessThanOrEqualsOperator extends BaseOperatorStrategy<\n  number | string | Date,\n  number | string | Date\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.LessThanOrEquals,\n    displayName: \"Less Than or Equals\",\n    category: OperatorCategory.COMPARISON,\n    description:\n      \"Checks if the field value is less than or equal to the constraint value\",\n    acceptedFieldTypes: [\"number\", \"string\", \"date\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"quantity\", operator: \"less-than-or-equals\", value: 10 }',\n  };\n\n  private equalsOperator = new EqualsOperator();\n  private lessThanOperator = new LessThanOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return (\n      this.equalsOperator.evaluate(context) ||\n      this.lessThanOperator.evaluate(context)\n    );\n  }\n\n  isValidFieldType(value: unknown): value is number | string | Date {\n    return this.lessThanOperator.isValidFieldType!(value);\n  }\n\n  isValidConstraintType(value: unknown): value is number | string | Date {\n    return this.lessThanOperator.isValidConstraintType!(value);\n  }\n}\n\n/**\n * In operator - checks if value is in array\n */\nexport class InOperator extends BaseOperatorStrategy<any, any[]> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.In,\n    displayName: \"In\",\n    category: OperatorCategory.COMPARISON,\n    description: \"Checks if the field value is in the provided array\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"status\", operator: \"in\", value: [\"active\", \"pending\"] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (!Array.isArray(constraintValue)) return false;\n    return constraintValue.includes(fieldValue);\n  }\n\n  isValidConstraintType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Not In operator\n */\nexport class NotInOperator extends BaseOperatorStrategy<any, any[]> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotIn,\n    displayName: \"Not In\",\n    category: OperatorCategory.COMPARISON,\n    description: \"Checks if the field value is not in the provided array\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"role\", operator: \"not-in\", value: [\"admin\", \"moderator\"] }',\n  };\n\n  private inOperator = new InOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.inOperator.evaluate(context);\n  }\n\n  isValidConstraintType(value: unknown): value is any[] {\n    return Array.isArray(value);\n  }\n}\n\n/**\n * Between operator - checks if value is between two values\n */\nexport class BetweenOperator extends BaseOperatorStrategy<\n  number,\n  [number, number]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Between,\n    displayName: \"Between\",\n    category: OperatorCategory.COMPARISON,\n    description: \"Checks if the field value is between two values (inclusive)\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"range\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"age\", operator: \"between\", value: [18, 65] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (!Array.isArray(constraintValue) || constraintValue.length !== 2)\n      return false;\n    if (typeof fieldValue !== \"number\") return false;\n\n    const [min, max] = constraintValue;\n    return fieldValue >= Number(min) && fieldValue <= Number(max);\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n\n  isValidConstraintType(value: unknown): value is [number, number] {\n    return (\n      Array.isArray(value) &&\n      value.length === 2 &&\n      typeof value[0] === \"number\" &&\n      typeof value[1] === \"number\"\n    );\n  }\n\n  override validate(\n    context: OperatorContext,\n  ): ReturnType<BaseOperatorStrategy[\"validate\"]> {\n    const baseValidation = super.validate(context);\n    if (!baseValidation.isValid) return baseValidation;\n\n    if (\n      Array.isArray(context.constraintValue) &&\n      context.constraintValue.length === 2\n    ) {\n      const [min, max] = context.constraintValue;\n      if (min > max) {\n        return {\n          isValid: false,\n          error: \"Minimum value cannot be greater than maximum value\",\n        };\n      }\n    }\n\n    return baseValidation;\n  }\n}\n\n/**\n * Not Between operator\n */\nexport class NotBetweenOperator extends BaseOperatorStrategy<\n  number,\n  [number, number]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotBetween,\n    displayName: \"Not Between\",\n    category: OperatorCategory.COMPARISON,\n    description: \"Checks if the field value is not between two values\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"range\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"temperature\", operator: \"not-between\", value: [0, 100] }',\n  };\n\n  private betweenOperator = new BetweenOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.betweenOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return this.betweenOperator.isValidFieldType!(value);\n  }\n\n  isValidConstraintType(value: unknown): value is [number, number] {\n    return this.betweenOperator.isValidConstraintType!(value);\n  }\n\n  override validate(\n    context: OperatorContext,\n  ): ReturnType<BaseOperatorStrategy[\"validate\"]> {\n    return this.betweenOperator.validate(context);\n  }\n}\n"
  },
  {
    "path": "packages/core/src/operators/implementations/date-time.ts",
    "content": "import { Operators } from \"@root/enums\";\nimport { OperatorCategory, BaseOperatorStrategy } from \"../base\";\nimport type { OperatorMetadata, OperatorContext } from \"../base\";\n\n/**\n * Helper function to parse dates\n */\nfunction parseDate(value: any): Date | null {\n  if (value instanceof Date) return value;\n  if (typeof value === \"string\" || typeof value === \"number\") {\n    const date = new Date(value);\n    return Number.isNaN(date.getTime()) ? null : date;\n  }\n  return null;\n}\n\n/**\n * Helper function to parse time strings (HH:MM:SS)\n */\nfunction parseTime(value: string): number | null {\n  const match = value.match(/^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/);\n  if (!match) return null;\n\n  const hours = Number.parseInt(match[1]!, 10);\n  const minutes = Number.parseInt(match[2]!, 10);\n  const seconds = match[3] ? Number.parseInt(match[3], 10) : 0;\n\n  if (\n    hours < 0 ||\n    hours > 23 ||\n    minutes < 0 ||\n    minutes > 59 ||\n    seconds < 0 ||\n    seconds > 59\n  ) {\n    return null;\n  }\n\n  return hours * 3600 + minutes * 60 + seconds;\n}\n\n/**\n * Date After operator\n */\nexport class DateAfterOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  Date | string | number\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateAfter,\n    displayName: \"Date After\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field date is after the provided date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"date\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"createdAt\", operator: \"date-after\", value: \"2025-01-01\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    const fieldDate = parseDate(fieldValue);\n    const constraintDate = parseDate(constraintValue);\n\n    if (!fieldDate || !constraintDate) return false;\n\n    return fieldDate > constraintDate;\n  }\n}\n\n/**\n * Date After Now operator\n */\nexport class DateAfterNowOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateAfterNow,\n    displayName: \"Date After Now\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field date is after the current date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: true,\n    example: '{ field: \"expiresAt\", operator: \"date-after-now\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    const fieldDate = parseDate(fieldValue);\n    if (!fieldDate) return false;\n\n    return fieldDate > new Date();\n  }\n}\n\n/**\n * Date Before operator\n */\nexport class DateBeforeOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  Date | string | number\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateBefore,\n    displayName: \"Date Before\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field date is before the provided date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"date\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"birthday\", operator: \"date-before\", value: \"2000-01-01\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    const fieldDate = parseDate(fieldValue);\n    const constraintDate = parseDate(constraintValue);\n\n    if (!fieldDate || !constraintDate) return false;\n\n    return fieldDate < constraintDate;\n  }\n}\n\n/**\n * Date Before Now operator\n */\nexport class DateBeforeNowOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateBeforeNow,\n    displayName: \"Date Before Now\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field date is before the current date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: true,\n    example: '{ field: \"startedAt\", operator: \"date-before-now\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    const fieldDate = parseDate(fieldValue);\n    if (!fieldDate) return false;\n\n    return fieldDate < new Date();\n  }\n}\n\n/**\n * Date Equals operator\n */\nexport class DateEqualsOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  Date | string | number\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateEquals,\n    displayName: \"Date Equals\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field date equals the provided date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"date\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"appointmentDate\", operator: \"date-equals\", value: \"2025-01-15\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    const fieldDate = parseDate(fieldValue);\n    const constraintDate = parseDate(constraintValue);\n\n    if (!fieldDate || !constraintDate) return false;\n\n    return fieldDate.getTime() === constraintDate.getTime();\n  }\n}\n\n/**\n * Date Equals To Now operator\n */\nexport class DateEqualsToNowOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateEqualsToNow,\n    displayName: \"Date Equals Now\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field date equals the current date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: true,\n    example: '{ field: \"todayDate\", operator: \"date-equals-to-now\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    const fieldDate = parseDate(fieldValue);\n    if (!fieldDate) return false;\n\n    const now = new Date();\n    // Compare only date parts, not time\n    return fieldDate.toDateString() === now.toDateString();\n  }\n}\n\n/**\n * Date Not Equals operator\n */\nexport class DateNotEqualsOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  Date | string | number\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateNotEquals,\n    displayName: \"Date Not Equals\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field date does not equal the provided date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"date\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"lastLogin\", operator: \"date-not-equals\", value: \"2025-01-01\" }',\n  };\n\n  private equalsOperator = new DateEqualsOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.equalsOperator.evaluate(context);\n  }\n}\n\n/**\n * Date After Or Equals operator\n */\nexport class DateAfterOrEqualsOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  Date | string | number\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateAfterOrEquals,\n    displayName: \"Date After Or Equals\",\n    category: OperatorCategory.DATE_TIME,\n    description:\n      \"Checks if the field date is after or equals the provided date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"date\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"startDate\", operator: \"date-after-or-equals\", value: \"2025-01-01\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    const fieldDate = parseDate(fieldValue);\n    const constraintDate = parseDate(constraintValue);\n\n    if (!fieldDate || !constraintDate) return false;\n\n    return fieldDate >= constraintDate;\n  }\n}\n\n/**\n * Date Before Or Equals operator\n */\nexport class DateBeforeOrEqualsOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  Date | string | number\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateBeforeOrEquals,\n    displayName: \"Date Before Or Equals\",\n    category: OperatorCategory.DATE_TIME,\n    description:\n      \"Checks if the field date is before or equals the provided date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"date\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"endDate\", operator: \"date-before-or-equals\", value: \"2025-12-31\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    const fieldDate = parseDate(fieldValue);\n    const constraintDate = parseDate(constraintValue);\n\n    if (!fieldDate || !constraintDate) return false;\n\n    return fieldDate <= constraintDate;\n  }\n}\n\n/**\n * Date Between operator\n */\nexport class DateBetweenOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  [Date | string | number, Date | string | number]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateBetween,\n    displayName: \"Date Between\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field date is between two dates\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"eventDate\", operator: \"date-between\", value: [\"2025-01-01\", \"2025-12-31\"] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (!Array.isArray(constraintValue) || constraintValue.length !== 2)\n      return false;\n\n    const fieldDate = parseDate(fieldValue);\n    const startDate = parseDate(constraintValue[0]);\n    const endDate = parseDate(constraintValue[1]);\n\n    if (!fieldDate || !startDate || !endDate) return false;\n\n    return fieldDate >= startDate && fieldDate <= endDate;\n  }\n\n  isValidConstraintType(value: unknown): value is [any, any] {\n    return Array.isArray(value) && value.length === 2;\n  }\n}\n\n/**\n * Date Not Between operator\n */\nexport class DateNotBetweenOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  [Date | string | number, Date | string | number]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateNotBetween,\n    displayName: \"Date Not Between\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field date is not between two dates\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"holiday\", operator: \"date-not-between\", value: [\"2025-06-01\", \"2025-08-31\"] }',\n  };\n\n  private betweenOperator = new DateBetweenOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.betweenOperator.evaluate(context);\n  }\n\n  isValidConstraintType(value: unknown): value is [any, any] {\n    return Array.isArray(value) && value.length === 2;\n  }\n}\n\n/**\n * Time After operator\n */\nexport class TimeAfterOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.TimeAfter,\n    displayName: \"Time After\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field time is after the provided time\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"openingTime\", operator: \"time-after\", value: \"09:00:00\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"string\")\n      return false;\n\n    const fieldTime = parseTime(fieldValue);\n    const constraintTime = parseTime(constraintValue);\n\n    if (fieldTime === null || constraintTime === null) return false;\n\n    return fieldTime > constraintTime;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Time Before operator\n */\nexport class TimeBeforeOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.TimeBefore,\n    displayName: \"Time Before\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field time is before the provided time\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"closingTime\", operator: \"time-before\", value: \"18:00:00\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"string\")\n      return false;\n\n    const fieldTime = parseTime(fieldValue);\n    const constraintTime = parseTime(constraintValue);\n\n    if (fieldTime === null || constraintTime === null) return false;\n\n    return fieldTime < constraintTime;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Time Equals operator\n */\nexport class TimeEqualsOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.TimeEquals,\n    displayName: \"Time Equals\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field time equals the provided time\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"meetingTime\", operator: \"time-equals\", value: \"14:30:00\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"string\")\n      return false;\n\n    const fieldTime = parseTime(fieldValue);\n    const constraintTime = parseTime(constraintValue);\n\n    if (fieldTime === null || constraintTime === null) return false;\n\n    return fieldTime === constraintTime;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Time Between operator\n */\nexport class TimeBetweenOperator extends BaseOperatorStrategy<\n  string,\n  [string, string]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.TimeBetween,\n    displayName: \"Time Between\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field time is between two times\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"workHours\", operator: \"time-between\", value: [\"09:00:00\", \"17:00:00\"] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (\n      typeof fieldValue !== \"string\" ||\n      !Array.isArray(constraintValue) ||\n      constraintValue.length !== 2\n    ) {\n      return false;\n    }\n\n    const fieldTime = parseTime(fieldValue);\n    const startTime = parseTime(constraintValue[0]);\n    const endTime = parseTime(constraintValue[1]);\n\n    if (fieldTime === null || startTime === null || endTime === null)\n      return false;\n\n    return fieldTime >= startTime && fieldTime <= endTime;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is [string, string] {\n    return (\n      Array.isArray(value) &&\n      value.length === 2 &&\n      typeof value[0] === \"string\" &&\n      typeof value[1] === \"string\"\n    );\n  }\n}\n\n/**\n * Date operator - checks if value is a valid date\n */\nexport class DateOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Date,\n    displayName: \"Is Date\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is a valid date\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"birthday\", operator: \"date\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    const date = parseDate(fieldValue);\n    return date !== null;\n  }\n}\n\n/**\n * Not Date operator\n */\nexport class NotDateOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotDate,\n    displayName: \"Is Not Date\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not a valid date\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"customField\", operator: \"not-date\" }',\n  };\n\n  private dateOperator = new DateOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.dateOperator.evaluate(context);\n  }\n}\n\n/**\n * Time After Or Equals operator\n */\nexport class TimeAfterOrEqualsOperator extends BaseOperatorStrategy<\n  string,\n  string\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.TimeAfterOrEquals,\n    displayName: \"Time After Or Equals\",\n    category: OperatorCategory.DATE_TIME,\n    description:\n      \"Checks if the field time is after or equal to the provided time\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"startTime\", operator: \"time-after-or-equals\", value: \"09:00:00\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"string\")\n      return false;\n\n    const fieldTime = parseTime(fieldValue);\n    const constraintTime = parseTime(constraintValue);\n\n    if (fieldTime === null || constraintTime === null) return false;\n\n    return fieldTime >= constraintTime;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Time Before Or Equals operator\n */\nexport class TimeBeforeOrEqualsOperator extends BaseOperatorStrategy<\n  string,\n  string\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.TimeBeforeOrEquals,\n    displayName: \"Time Before Or Equals\",\n    category: OperatorCategory.DATE_TIME,\n    description:\n      \"Checks if the field time is before or equal to the provided time\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"endTime\", operator: \"time-before-or-equals\", value: \"17:00:00\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"string\")\n      return false;\n\n    const fieldTime = parseTime(fieldValue);\n    const constraintTime = parseTime(constraintValue);\n\n    if (fieldTime === null || constraintTime === null) return false;\n\n    return fieldTime <= constraintTime;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Time Not Equals operator\n */\nexport class TimeNotEqualsOperator extends BaseOperatorStrategy<\n  string,\n  string\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.TimeNotEquals,\n    displayName: \"Time Not Equals\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field time does not equal the provided time\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"breakTime\", operator: \"time-not-equals\", value: \"12:00:00\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"string\")\n      return false;\n\n    const fieldTime = parseTime(fieldValue);\n    const constraintTime = parseTime(constraintValue);\n\n    if (fieldTime === null || constraintTime === null) return false;\n\n    return fieldTime !== constraintTime;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Time Not Between operator\n */\nexport class TimeNotBetweenOperator extends BaseOperatorStrategy<\n  string,\n  [string, string]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.TimeNotBetween,\n    displayName: \"Time Not Between\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field time is not between two times\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"breakTime\", operator: \"time-not-between\", value: [\"09:00:00\", \"17:00:00\"] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (\n      typeof fieldValue !== \"string\" ||\n      !Array.isArray(constraintValue) ||\n      constraintValue.length !== 2\n    ) {\n      return false;\n    }\n\n    const fieldTime = parseTime(fieldValue);\n    const startTime = parseTime(constraintValue[0]);\n    const endTime = parseTime(constraintValue[1]);\n\n    if (fieldTime === null || startTime === null || endTime === null)\n      return false;\n\n    return fieldTime < startTime || fieldTime > endTime;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is [string, string] {\n    return (\n      Array.isArray(value) &&\n      value.length === 2 &&\n      typeof value[0] === \"string\" &&\n      typeof value[1] === \"string\"\n    );\n  }\n}\n\n/**\n * Date Not Equals To Now operator\n */\nexport class DateNotEqualsToNowOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateNotEqualsToNow,\n    displayName: \"Date Not Equals Now\",\n    category: OperatorCategory.DATE_TIME,\n    description: \"Checks if the field date does not equal the current date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: true,\n    example: '{ field: \"eventDate\", operator: \"date-not-equals-to-now\" }',\n  };\n\n  private equalsToNowOperator = new DateEqualsToNowOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.equalsToNowOperator.evaluate(context);\n  }\n}\n\n/**\n * Date After Now Or Equals operator\n */\nexport class DateAfterNowOrEqualsOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateAfterNowOrEquals,\n    displayName: \"Date After Now Or Equals\",\n    category: OperatorCategory.DATE_TIME,\n    description:\n      \"Checks if the field date is after or equal to the current date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: true,\n    example: '{ field: \"validUntil\", operator: \"date-after-now-or-equals\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    const fieldDate = parseDate(fieldValue);\n    if (!fieldDate) return false;\n\n    return fieldDate >= new Date();\n  }\n}\n\n/**\n * Date Before Now Or Equals operator\n */\nexport class DateBeforeNowOrEqualsOperator extends BaseOperatorStrategy<\n  Date | string | number,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.DateBeforeNowOrEquals,\n    displayName: \"Date Before Now Or Equals\",\n    category: OperatorCategory.DATE_TIME,\n    description:\n      \"Checks if the field date is before or equal to the current date\",\n    acceptedFieldTypes: [\"date\", \"string\", \"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: true,\n    example: '{ field: \"dueDate\", operator: \"date-before-now-or-equals\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    const fieldDate = parseDate(fieldValue);\n    if (!fieldDate) return false;\n\n    return fieldDate <= new Date();\n  }\n}\n"
  },
  {
    "path": "packages/core/src/operators/implementations/existence.ts",
    "content": "import { Operators } from \"@root/enums\";\nimport { OperatorCategory, BaseOperatorStrategy } from \"../base\";\nimport type { OperatorMetadata, OperatorContext } from \"../base\";\n\n/**\n * Exists operator - checks if field exists\n */\nexport class ExistsOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Exists,\n    displayName: \"Exists\",\n    category: OperatorCategory.EXISTENCE,\n    description: \"Checks if the field exists in the object\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"email\", operator: \"exists\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    // For exists check, the fieldValue will be undefined if the field doesn't exist\n    // We also need to check if the field path exists in the criteria\n    const { fieldValue, criteria } = context;\n\n    // If no criteria is provided, we can't check existence\n    if (!criteria) {\n      return fieldValue !== undefined;\n    }\n\n    // Check if the field exists - if fieldValue is not undefined, the field exists\n    return fieldValue !== undefined;\n  }\n}\n\n/**\n * Not Exists operator\n */\nexport class NotExistsOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotExists,\n    displayName: \"Not Exists\",\n    category: OperatorCategory.EXISTENCE,\n    description: \"Checks if the field does not exist in the object\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"deletedAt\", operator: \"not-exists\" }',\n  };\n\n  private existsOperator = new ExistsOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.existsOperator.evaluate(context);\n  }\n}\n\n/**\n * Null Or Undefined operator\n */\nexport class NullOrUndefinedOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NullOrUndefined,\n    displayName: \"Null or Undefined\",\n    category: OperatorCategory.EXISTENCE,\n    description: \"Checks if the field value is null or undefined\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"middleName\", operator: \"null-or-undefined\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return fieldValue === null || fieldValue === undefined;\n  }\n}\n\n/**\n * Not Null Or Undefined operator\n */\nexport class NotNullOrUndefinedOperator extends BaseOperatorStrategy<\n  any,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotNullOrUndefined,\n    displayName: \"Not Null or Undefined\",\n    category: OperatorCategory.EXISTENCE,\n    description: \"Checks if the field value is not null or undefined\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"requiredField\", operator: \"not-null-or-undefined\" }',\n  };\n\n  private nullOrUndefinedOperator = new NullOrUndefinedOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.nullOrUndefinedOperator.evaluate(context);\n  }\n}\n\n/**\n * Empty operator - checks if value is empty\n */\nexport class EmptyOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Empty,\n    displayName: \"Empty\",\n    category: OperatorCategory.EXISTENCE,\n    description:\n      \"Checks if the field value is empty (string, array, or object)\",\n    acceptedFieldTypes: [\"string\", \"array\", \"object\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"description\", operator: \"empty\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (fieldValue === null || fieldValue === undefined) return true;\n\n    if (typeof fieldValue === \"string\") {\n      return fieldValue.length === 0;\n    }\n\n    if (Array.isArray(fieldValue)) {\n      return fieldValue.length === 0;\n    }\n\n    if (typeof fieldValue === \"object\") {\n      return Object.keys(fieldValue).length === 0;\n    }\n\n    return false;\n  }\n}\n\n/**\n * Not Empty operator\n */\nexport class NotEmptyOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotEmpty,\n    displayName: \"Not Empty\",\n    category: OperatorCategory.EXISTENCE,\n    description: \"Checks if the field value is not empty\",\n    acceptedFieldTypes: [\"string\", \"array\", \"object\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"name\", operator: \"not-empty\" }',\n  };\n\n  private emptyOperator = new EmptyOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.emptyOperator.evaluate(context);\n  }\n}\n\n/**\n * Null Or White Space operator\n */\nexport class NullOrWhiteSpaceOperator extends BaseOperatorStrategy<\n  string,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NullOrWhiteSpace,\n    displayName: \"Null or White Space\",\n    category: OperatorCategory.EXISTENCE,\n    description:\n      \"Checks if the field value is null, undefined, or contains only whitespace\",\n    acceptedFieldTypes: [\"string\", \"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"comment\", operator: \"null-or-white-space\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (fieldValue === null || fieldValue === undefined) return true;\n\n    if (typeof fieldValue === \"string\") {\n      return fieldValue.trim().length === 0;\n    }\n\n    return false;\n  }\n}\n\n/**\n * Not Null Or White Space operator\n */\nexport class NotNullOrWhiteSpaceOperator extends BaseOperatorStrategy<\n  string,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotNullOrWhiteSpace,\n    displayName: \"Not Null or White Space\",\n    category: OperatorCategory.EXISTENCE,\n    description:\n      \"Checks if the field value is not null, undefined, or whitespace\",\n    acceptedFieldTypes: [\"string\", \"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"username\", operator: \"not-null-or-white-space\" }',\n  };\n\n  private nullOrWhiteSpaceOperator = new NullOrWhiteSpaceOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.nullOrWhiteSpaceOperator.evaluate(context);\n  }\n}\n"
  },
  {
    "path": "packages/core/src/operators/implementations/index.ts",
    "content": "export * from \"./array\";\nexport * from \"./boolean\";\n// Comparison operators\nexport * from \"./comparison\";\nexport * from \"./date-time\";\nexport * from \"./existence\";\nexport * from \"./numeric\";\nexport * from \"./pattern\";\nexport * from \"./string\";\nexport * from \"./type\";\n"
  },
  {
    "path": "packages/core/src/operators/implementations/numeric.ts",
    "content": "import { Operators } from \"@root/enums\";\nimport { OperatorCategory, BaseOperatorStrategy } from \"../base\";\nimport type { OperatorMetadata, OperatorContext } from \"../base\";\nimport { isNumberOperator } from \"@root/operators\";\n\n/**\n * Numeric operator - checks if value is numeric\n */\nexport class NumericOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Numeric,\n    displayName: \"Is Numeric\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is numeric\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"quantity\", operator: \"numeric\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (typeof fieldValue === \"number\") {\n      return !Number.isNaN(fieldValue) && Number.isFinite(fieldValue);\n    }\n\n    if (typeof fieldValue === \"string\") {\n      const num = Number(fieldValue);\n      return !Number.isNaN(num) && Number.isFinite(num);\n    }\n\n    return false;\n  }\n}\n\n/**\n * Not Numeric operator\n */\nexport class NotNumericOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotNumeric,\n    displayName: \"Is Not Numeric\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not numeric\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"code\", operator: \"not-numeric\" }',\n  };\n\n  private numericOperator = new NumericOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.numericOperator.evaluate(context);\n  }\n}\n\n/**\n * Number operator - checks if value is a number type\n */\nexport class NumberOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Number,\n    displayName: \"Is Number\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is a number type\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"age\", operator: \"number\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return isNumberOperator(fieldValue);\n  }\n}\n\n/**\n * Not Number operator\n */\nexport class NotNumberOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotNumber,\n    displayName: \"Is Not Number\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not a number type\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"id\", operator: \"not-number\" }',\n  };\n\n  private numberOperator = new NumberOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.numberOperator.evaluate(context);\n  }\n}\n\n/**\n * Integer operator\n */\nexport class IntegerOperator extends BaseOperatorStrategy<number, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Integer,\n    displayName: \"Is Integer\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is an integer\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"count\", operator: \"integer\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return typeof fieldValue === \"number\" && Number.isInteger(fieldValue);\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Not Integer operator\n */\nexport class NotIntegerOperator extends BaseOperatorStrategy<number, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotInteger,\n    displayName: \"Is Not Integer\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not an integer\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"price\", operator: \"not-integer\" }',\n  };\n\n  private integerOperator = new IntegerOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.integerOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Float operator\n */\nexport class FloatOperator extends BaseOperatorStrategy<number, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Float,\n    displayName: \"Is Float\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is a float\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"temperature\", operator: \"float\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return typeof fieldValue === \"number\" && !Number.isInteger(fieldValue);\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Not Float operator\n */\nexport class NotFloatOperator extends BaseOperatorStrategy<number, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotFloat,\n    displayName: \"Is Not Float\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not a float\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"quantity\", operator: \"not-float\" }',\n  };\n\n  private floatOperator = new FloatOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.floatOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Positive operator\n */\nexport class PositiveOperator extends BaseOperatorStrategy<number, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Positive,\n    displayName: \"Is Positive\",\n    category: OperatorCategory.NUMERIC,\n    description: \"Checks if the field value is positive\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"balance\", operator: \"positive\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return typeof fieldValue === \"number\" && fieldValue > 0;\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Not Positive operator\n */\nexport class NotPositiveOperator extends BaseOperatorStrategy<number, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotPositive,\n    displayName: \"Is Not Positive\",\n    category: OperatorCategory.NUMERIC,\n    description: \"Checks if the field value is not positive\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"debt\", operator: \"not-positive\" }',\n  };\n\n  private positiveOperator = new PositiveOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.positiveOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Negative operator\n */\nexport class NegativeOperator extends BaseOperatorStrategy<number, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Negative,\n    displayName: \"Is Negative\",\n    category: OperatorCategory.NUMERIC,\n    description: \"Checks if the field value is negative\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"loss\", operator: \"negative\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return typeof fieldValue === \"number\" && fieldValue < 0;\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Not Negative operator\n */\nexport class NotNegativeOperator extends BaseOperatorStrategy<number, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotNegative,\n    displayName: \"Is Not Negative\",\n    category: OperatorCategory.NUMERIC,\n    description: \"Checks if the field value is not negative\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"score\", operator: \"not-negative\" }',\n  };\n\n  private negativeOperator = new NegativeOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.negativeOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Zero operator\n */\nexport class ZeroOperator extends BaseOperatorStrategy<number, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Zero,\n    displayName: \"Is Zero\",\n    category: OperatorCategory.NUMERIC,\n    description: \"Checks if the field value is zero\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"remainder\", operator: \"zero\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return fieldValue === 0;\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Not Zero operator\n */\nexport class NotZeroOperator extends BaseOperatorStrategy<number, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotZero,\n    displayName: \"Is Not Zero\",\n    category: OperatorCategory.NUMERIC,\n    description: \"Checks if the field value is not zero\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"divisor\", operator: \"not-zero\" }',\n  };\n\n  private zeroOperator = new ZeroOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.zeroOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Min operator - minimum value check\n */\nexport class MinOperator extends BaseOperatorStrategy<number, number> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Min,\n    displayName: \"Minimum\",\n    category: OperatorCategory.NUMERIC,\n    description:\n      \"Checks if the field value is greater than or equal to the minimum\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"age\", operator: \"min\", value: 18 }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"number\" || typeof constraintValue !== \"number\") {\n      return false;\n    }\n\n    return fieldValue >= constraintValue;\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n\n  isValidConstraintType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Max operator - maximum value check\n */\nexport class MaxOperator extends BaseOperatorStrategy<number, number> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Max,\n    displayName: \"Maximum\",\n    category: OperatorCategory.NUMERIC,\n    description:\n      \"Checks if the field value is less than or equal to the maximum\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"discount\", operator: \"max\", value: 50 }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"number\" || typeof constraintValue !== \"number\") {\n      return false;\n    }\n\n    return fieldValue <= constraintValue;\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n\n  isValidConstraintType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Number Between operator\n */\nexport class NumberBetweenOperator extends BaseOperatorStrategy<\n  number,\n  [number, number]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NumberBetween,\n    displayName: \"Number Between\",\n    category: OperatorCategory.NUMERIC,\n    description: \"Checks if the field value is between two numbers\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"score\", operator: \"number-between\", value: [0, 100] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (\n      typeof fieldValue !== \"number\" ||\n      !Array.isArray(constraintValue) ||\n      constraintValue.length !== 2 ||\n      typeof constraintValue[0] !== \"number\" ||\n      typeof constraintValue[1] !== \"number\"\n    ) {\n      return false;\n    }\n\n    const [min, max] = constraintValue;\n    return fieldValue >= min && fieldValue <= max;\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n\n  isValidConstraintType(value: unknown): value is [number, number] {\n    return (\n      Array.isArray(value) &&\n      value.length === 2 &&\n      typeof value[0] === \"number\" &&\n      typeof value[1] === \"number\"\n    );\n  }\n}\n\n/**\n * Not Number Between operator\n */\nexport class NotNumberBetweenOperator extends BaseOperatorStrategy<\n  number,\n  [number, number]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotNumberBetween,\n    displayName: \"Not Number Between\",\n    category: OperatorCategory.NUMERIC,\n    description: \"Checks if the field value is not between two numbers\",\n    acceptedFieldTypes: [\"number\"],\n    expectedValueType: \"array\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"temperature\", operator: \"not-number-between\", value: [-10, 40] }',\n  };\n\n  private betweenOperator = new NumberBetweenOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.betweenOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n\n  isValidConstraintType(value: unknown): value is [number, number] {\n    return (\n      Array.isArray(value) &&\n      value.length === 2 &&\n      typeof value[0] === \"number\" &&\n      typeof value[1] === \"number\"\n    );\n  }\n}\n"
  },
  {
    "path": "packages/core/src/operators/implementations/pattern.ts",
    "content": "import { Operators } from \"@root/enums\";\nimport { OperatorCategory, BaseOperatorStrategy } from \"../base\";\nimport type { OperatorMetadata, OperatorContext } from \"../base\";\nimport { isPersianAlphaOperator } from \"@root/operators\";\n\n/**\n * Email operator - validates email format\n */\nexport class EmailOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Email,\n    displayName: \"Is Email\",\n    category: OperatorCategory.PATTERN,\n    description: \"Checks if the field value is a valid email address\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"contactEmail\", operator: \"email\" }',\n  };\n\n  private readonly emailRegex = /^[\\w.%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$/i;\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n\n    return this.emailRegex.test(fieldValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not Email operator\n */\nexport class NotEmailOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotEmail,\n    displayName: \"Is Not Email\",\n    category: OperatorCategory.PATTERN,\n    description: \"Checks if the field value is not a valid email address\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"username\", operator: \"not-email\" }',\n  };\n\n  private emailOperator = new EmailOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.emailOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * URL operator - validates URL format\n */\nexport class UrlOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Url,\n    displayName: \"Is URL\",\n    category: OperatorCategory.PATTERN,\n    description: \"Checks if the field value is a valid URL\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"website\", operator: \"url\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n\n    try {\n      new URL(fieldValue);\n      return true;\n    } catch {\n      return false;\n    }\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not URL operator\n */\nexport class NotUrlOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotUrl,\n    displayName: \"Is Not URL\",\n    category: OperatorCategory.PATTERN,\n    description: \"Checks if the field value is not a valid URL\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"reference\", operator: \"not-url\" }',\n  };\n\n  private urlOperator = new UrlOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.urlOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * UUID operator - validates UUID format\n */\nexport class UUIDOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.UUID,\n    displayName: \"Is UUID\",\n    category: OperatorCategory.PATTERN,\n    description: \"Checks if the field value is a valid UUID\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"id\", operator: \"uuid\" }',\n  };\n\n  private readonly uuidRegex =\n    /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n\n    return this.uuidRegex.test(fieldValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not UUID operator\n */\nexport class NotUUIDOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotUUID,\n    displayName: \"Is Not UUID\",\n    category: OperatorCategory.PATTERN,\n    description: \"Checks if the field value is not a valid UUID\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"code\", operator: \"not-uuid\" }',\n  };\n\n  private uuidOperator = new UUIDOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.uuidOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Alpha operator - checks if string contains only letters\n */\nexport class AlphaOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Alpha,\n    displayName: \"Is Alpha\",\n    category: OperatorCategory.PATTERN,\n    description:\n      \"Checks if the field value contains only alphabetic characters\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"firstName\", operator: \"alpha\" }',\n  };\n\n  private readonly alphaRegex = /^[a-z]+$/i;\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n\n    return this.alphaRegex.test(fieldValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not Alpha operator\n */\nexport class NotAlphaOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotAlpha,\n    displayName: \"Is Not Alpha\",\n    category: OperatorCategory.PATTERN,\n    description:\n      \"Checks if the field value does not contain only alphabetic characters\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"password\", operator: \"not-alpha\" }',\n  };\n\n  private alphaOperator = new AlphaOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.alphaOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * AlphaNumeric operator - checks if string contains only letters and numbers\n */\nexport class AlphaNumericOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.AlphaNumeric,\n    displayName: \"Is AlphaNumeric\",\n    category: OperatorCategory.PATTERN,\n    description:\n      \"Checks if the field value contains only alphanumeric characters\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"username\", operator: \"alpha-numeric\" }',\n  };\n\n  private readonly alphaNumericRegex = /^[a-z0-9]+$/i;\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n\n    return this.alphaNumericRegex.test(fieldValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not AlphaNumeric operator\n */\nexport class NotAlphaNumericOperator extends BaseOperatorStrategy<\n  string,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotAlphaNumeric,\n    displayName: \"Is Not AlphaNumeric\",\n    category: OperatorCategory.PATTERN,\n    description:\n      \"Checks if the field value does not contain only alphanumeric characters\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"specialCode\", operator: \"not-alpha-numeric\" }',\n  };\n\n  private alphaNumericOperator = new AlphaNumericOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.alphaNumericOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Persian Alpha operator\n */\nexport class PersianAlphaOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.PersianAlpha,\n    displayName: \"Is Persian Alpha\",\n    category: OperatorCategory.PATTERN,\n    description:\n      \"Checks if the field value contains only Persian alphabetic characters\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"persianName\", operator: \"persian-alpha\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n\n    return isPersianAlphaOperator(fieldValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not Persian Alpha operator\n */\nexport class NotPersianAlphaOperator extends BaseOperatorStrategy<\n  string,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotPersianAlpha,\n    displayName: \"Is Not Persian Alpha\",\n    category: OperatorCategory.PATTERN,\n    description:\n      \"Checks if the field value does not contain only Persian alphabetic characters\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"englishName\", operator: \"not-persian-alpha\" }',\n  };\n\n  private persianAlphaOperator = new PersianAlphaOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.persianAlphaOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Persian AlphaNumeric operator\n */\nexport class PersianAlphaNumericOperator extends BaseOperatorStrategy<\n  string,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.PersianAlphaNumeric,\n    displayName: \"Is Persian AlphaNumeric\",\n    category: OperatorCategory.PATTERN,\n    description:\n      \"Checks if the field value contains only Persian alphanumeric characters\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"persianCode\", operator: \"persian-alpha-numeric\" }',\n  };\n\n  private readonly persianAlphaNumericRegex = /^[\\u0600-\\u06FF\\s0-9]+$/;\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n\n    return this.persianAlphaNumericRegex.test(fieldValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not Persian AlphaNumeric operator\n */\nexport class NotPersianAlphaNumericOperator extends BaseOperatorStrategy<\n  string,\n  void\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotPersianAlphaNumeric,\n    displayName: \"Is Not Persian AlphaNumeric\",\n    category: OperatorCategory.PATTERN,\n    description:\n      \"Checks if the field value does not contain only Persian alphanumeric characters\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"mixedCode\", operator: \"not-persian-alpha-numeric\" }',\n  };\n\n  private persianAlphaNumericOperator = new PersianAlphaNumericOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.persianAlphaNumericOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Lower Case operator\n */\nexport class LowerCaseOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.LowerCase,\n    displayName: \"Is Lower Case\",\n    category: OperatorCategory.PATTERN,\n    description: \"Checks if the field value is in lower case\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"code\", operator: \"lower-case\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n\n    return fieldValue === fieldValue.toLowerCase() && /[a-z]/.test(fieldValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not Lower Case operator\n */\nexport class NotLowerCaseOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotLowerCase,\n    displayName: \"Is Not Lower Case\",\n    category: OperatorCategory.PATTERN,\n    description: \"Checks if the field value is not in lower case\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"title\", operator: \"not-lower-case\" }',\n  };\n\n  private lowerCaseOperator = new LowerCaseOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.lowerCaseOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Upper Case operator\n */\nexport class UpperCaseOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.UpperCase,\n    displayName: \"Is Upper Case\",\n    category: OperatorCategory.PATTERN,\n    description: \"Checks if the field value is in upper case\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"constant\", operator: \"upper-case\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n\n    return fieldValue === fieldValue.toUpperCase() && /[A-Z]/.test(fieldValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not Upper Case operator\n */\nexport class NotUpperCaseOperator extends BaseOperatorStrategy<string, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotUpperCase,\n    displayName: \"Is Not Upper Case\",\n    category: OperatorCategory.PATTERN,\n    description: \"Checks if the field value is not in upper case\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"description\", operator: \"not-upper-case\" }',\n  };\n\n  private upperCaseOperator = new UpperCaseOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.upperCaseOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n"
  },
  {
    "path": "packages/core/src/operators/implementations/string.ts",
    "content": "import { Operators } from \"@root/enums\";\nimport { OperatorCategory, BaseOperatorStrategy } from \"../base\";\nimport type { OperatorMetadata, OperatorContext } from \"../base\";\n\n/**\n * Like operator - SQL-like pattern matching\n */\nexport class LikeOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Like,\n    displayName: \"Like\",\n    category: OperatorCategory.STRING,\n    description: \"Performs SQL-like pattern matching with % and _ wildcards\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"email\", operator: \"like\", value: \"%@gmail.com\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"string\")\n      return false;\n\n    return this.performLikeMatch(fieldValue, constraintValue);\n  }\n\n  private performLikeMatch(\n    text: string,\n    pattern: string,\n    caseInsensitive = false,\n  ): boolean {\n    // Escape special regex characters except our wildcards\n    const escapedPattern = pattern.replace(/([\\\\.^$*+?()[\\]{}|])/g, \"\\\\$1\");\n\n    // Build the regular expression with pattern handling\n    let regexStr = \"^\";\n    let i = 0;\n\n    while (i < escapedPattern.length) {\n      const char = escapedPattern[i];\n\n      if (char === \"%\" && (i === 0 || escapedPattern[i - 1] !== \"\\\\\")) {\n        // % matches any sequence of characters\n        regexStr += \".*\";\n      } else if (char === \"_\" && (i === 0 || escapedPattern[i - 1] !== \"\\\\\")) {\n        // _ matches exactly one character\n        regexStr += \".\";\n      } else if (char === \"\\\\\" && i + 1 < escapedPattern.length) {\n        // Handle escaped characters\n        i++;\n        regexStr += escapedPattern[i];\n      } else {\n        regexStr += char;\n      }\n      i++;\n    }\n\n    regexStr += \"$\";\n\n    return new RegExp(regexStr, caseInsensitive ? \"i\" : undefined).test(text);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Not Like operator\n */\nexport class NotLikeOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotLike,\n    displayName: \"Not Like\",\n    category: OperatorCategory.STRING,\n    description: \"Performs negated SQL-like pattern matching\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"filename\", operator: \"not-like\", value: \"%.tmp\" }',\n  };\n\n  private likeOperator = new LikeOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.likeOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Starts With operator\n */\nexport class StartsWithOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.StartsWith,\n    displayName: \"Starts With\",\n    category: OperatorCategory.STRING,\n    description: \"Checks if the string starts with the specified value\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"url\", operator: \"starts-with\", value: \"https://\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"string\")\n      return false;\n\n    return fieldValue.startsWith(constraintValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Ends With operator\n */\nexport class EndsWithOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.EndsWith,\n    displayName: \"Ends With\",\n    category: OperatorCategory.STRING,\n    description: \"Checks if the string ends with the specified value\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"email\", operator: \"ends-with\", value: \".com\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"string\")\n      return false;\n\n    return fieldValue.endsWith(constraintValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * Contains substring operator\n */\nexport class ContainsStringOperator extends BaseOperatorStrategy<\n  string,\n  string\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.ContainsString,\n    displayName: \"Contains String\",\n    category: OperatorCategory.STRING,\n    description: \"Checks if the string contains the specified substring\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"description\", operator: \"contains-string\", value: \"error\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"string\")\n      return false;\n\n    return fieldValue.includes(constraintValue);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n}\n\n/**\n * String Length operator\n */\nexport class StringLengthOperator extends BaseOperatorStrategy<string, number> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.StringLength,\n    displayName: \"String Length\",\n    category: OperatorCategory.STRING,\n    description: \"Checks if the string length equals the specified value\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"code\", operator: \"string-length\", value: 6 }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"number\")\n      return false;\n\n    return fieldValue.length === constraintValue;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Min Length operator\n */\nexport class MinLengthOperator extends BaseOperatorStrategy<string, number> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.MinLength,\n    displayName: \"Minimum Length\",\n    category: OperatorCategory.STRING,\n    description: \"Checks if the string length is at least the specified value\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"password\", operator: \"min-length\", value: 8 }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"number\")\n      return false;\n\n    return fieldValue.length >= constraintValue;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Max Length operator\n */\nexport class MaxLengthOperator extends BaseOperatorStrategy<string, number> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.MaxLength,\n    displayName: \"Maximum Length\",\n    category: OperatorCategory.STRING,\n    description: \"Checks if the string length is at most the specified value\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"username\", operator: \"max-length\", value: 20 }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"number\")\n      return false;\n\n    return fieldValue.length <= constraintValue;\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Length Between operator\n */\nexport class LengthBetweenOperator extends BaseOperatorStrategy<\n  string,\n  [number, number]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.LengthBetween,\n    displayName: \"Length Between\",\n    category: OperatorCategory.STRING,\n    description:\n      \"Checks if the string length is between two values (inclusive)\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"range\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"title\", operator: \"length-between\", value: [10, 100] }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\") return false;\n    if (!Array.isArray(constraintValue) || constraintValue.length !== 2)\n      return false;\n\n    const [min, max] = constraintValue;\n    return fieldValue.length >= Number(min) && fieldValue.length <= Number(max);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is [number, number] {\n    return (\n      Array.isArray(value) &&\n      value.length === 2 &&\n      typeof value[0] === \"number\" &&\n      typeof value[1] === \"number\"\n    );\n  }\n\n  override validate(\n    context: OperatorContext,\n  ): ReturnType<BaseOperatorStrategy[\"validate\"]> {\n    const baseValidation = super.validate(context);\n    if (!baseValidation.isValid) return baseValidation;\n\n    if (\n      Array.isArray(context.constraintValue) &&\n      context.constraintValue.length === 2\n    ) {\n      const [min, max] = context.constraintValue;\n      if (min > max) {\n        return {\n          isValid: false,\n          error: \"Minimum length cannot be greater than maximum length\",\n        };\n      }\n      if (min < 0) {\n        return {\n          isValid: false,\n          error: \"Minimum length cannot be negative\",\n        };\n      }\n    }\n\n    return baseValidation;\n  }\n}\n\n/**\n * Not Length Between operator\n */\nexport class NotLengthBetweenOperator extends BaseOperatorStrategy<\n  string,\n  [number, number]\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotLengthBetween,\n    displayName: \"Not Length Between\",\n    category: OperatorCategory.STRING,\n    description: \"Checks if the string length is not between two values\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"range\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"code\", operator: \"not-length-between\", value: [5, 10] }',\n  };\n\n  private lengthBetweenOperator = new LengthBetweenOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.lengthBetweenOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is [number, number] {\n    return (\n      Array.isArray(value) &&\n      value.length === 2 &&\n      typeof value[0] === \"number\" &&\n      typeof value[1] === \"number\"\n    );\n  }\n}\n\n/**\n * Not String Length operator\n */\nexport class NotStringLengthOperator extends BaseOperatorStrategy<\n  string,\n  number\n> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotStringLength,\n    displayName: \"Not String Length\",\n    category: OperatorCategory.STRING,\n    description:\n      \"Checks if the string length is not equal to the specified value\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"number\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"postal_code\", operator: \"not-string-length\", value: 5 }',\n  };\n\n  private stringLengthOperator = new StringLengthOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.stringLengthOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is number {\n    return typeof value === \"number\";\n  }\n}\n\n/**\n * Matches operator - regex pattern matching\n */\nexport class MatchesOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Matches,\n    displayName: \"Matches Pattern\",\n    category: OperatorCategory.PATTERN,\n    description:\n      \"Checks if the field value matches the regular expression pattern\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example:\n      '{ field: \"email\", operator: \"matches\", value: \"^[\\\\w]+@[\\\\w]+\\\\.[\\\\w]+$\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue, constraintValue } = context;\n\n    if (typeof fieldValue !== \"string\" || typeof constraintValue !== \"string\") {\n      return false;\n    }\n\n    // Empty pattern should return false\n    if (constraintValue.length === 0) {\n      return false;\n    }\n\n    try {\n      let pattern = constraintValue;\n      // Handle regex delimiters like /pattern/\n      if (pattern.startsWith(\"/\") && pattern.endsWith(\"/\")) {\n        pattern = pattern.slice(1, -1);\n      }\n      const regex = new RegExp(pattern);\n      return regex.test(fieldValue);\n    } catch {\n      return false;\n    }\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  override validate(\n    context: OperatorContext,\n  ): ReturnType<BaseOperatorStrategy[\"validate\"]> {\n    const baseValidation = super.validate(context);\n    if (!baseValidation.isValid) return baseValidation;\n\n    if (typeof context.constraintValue === \"string\") {\n      // Empty pattern is invalid\n      if (context.constraintValue.length === 0) {\n        return {\n          isValid: false,\n          error: \"Pattern cannot be empty\",\n        };\n      }\n\n      try {\n        let pattern = context.constraintValue;\n        // Handle regex delimiters\n        if (pattern.startsWith(\"/\") && pattern.endsWith(\"/\")) {\n          pattern = pattern.slice(1, -1);\n        }\n\n        new RegExp(pattern);\n      } catch (error) {\n        return {\n          isValid: false,\n          error: `Invalid regular expression: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n        };\n      }\n    }\n\n    return baseValidation;\n  }\n}\n\n/**\n * Not Matches operator\n */\nexport class NotMatchesOperator extends BaseOperatorStrategy<string, string> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotMatches,\n    displayName: \"Not Matches Pattern\",\n    category: OperatorCategory.PATTERN,\n    description:\n      \"Checks if the field value does not match the regular expression pattern\",\n    acceptedFieldTypes: [\"string\"],\n    expectedValueType: \"string\",\n    requiresValue: true,\n    isNegatable: true,\n    example: '{ field: \"name\", operator: \"not-matches\", value: \"^[0-9]+$\" }',\n  };\n\n  private matchesOperator = new MatchesOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.matchesOperator.evaluate(context);\n  }\n\n  isValidFieldType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  isValidConstraintType(value: unknown): value is string {\n    return typeof value === \"string\";\n  }\n\n  override validate(\n    context: OperatorContext,\n  ): ReturnType<BaseOperatorStrategy[\"validate\"]> {\n    return this.matchesOperator.validate(context);\n  }\n}\n"
  },
  {
    "path": "packages/core/src/operators/implementations/type.ts",
    "content": "import { Operators } from \"@root/enums\";\nimport { OperatorCategory, BaseOperatorStrategy } from \"../base\";\nimport type { OperatorMetadata, OperatorContext } from \"../base\";\n\n/**\n * String operator - checks if value is a string\n */\nexport class StringOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.String,\n    displayName: \"Is String\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is a string\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"name\", operator: \"string\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return typeof fieldValue === \"string\";\n  }\n}\n\n/**\n * Not String operator\n */\nexport class NotStringOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotString,\n    displayName: \"Is Not String\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not a string\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"id\", operator: \"not-string\" }',\n  };\n\n  private stringOperator = new StringOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.stringOperator.evaluate(context);\n  }\n}\n\n/**\n * Object operator - checks if value is an object\n */\nexport class ObjectOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Object,\n    displayName: \"Is Object\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is an object\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"metadata\", operator: \"object\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return (\n      fieldValue !== null &&\n      typeof fieldValue === \"object\" &&\n      !Array.isArray(fieldValue)\n    );\n  }\n}\n\n/**\n * Not Object operator\n */\nexport class NotObjectOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotObject,\n    displayName: \"Is Not Object\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not an object\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"value\", operator: \"not-object\" }',\n  };\n\n  private objectOperator = new ObjectOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.objectOperator.evaluate(context);\n  }\n}\n\n/**\n * Array operator - checks if value is an array\n */\nexport class ArrayOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.Array,\n    displayName: \"Is Array\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is an array\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"tags\", operator: \"array\" }',\n  };\n\n  evaluate(context: OperatorContext): boolean {\n    const { fieldValue } = context;\n    return Array.isArray(fieldValue);\n  }\n}\n\n/**\n * Not Array operator\n */\nexport class NotArrayOperator extends BaseOperatorStrategy<any, void> {\n  readonly metadata: OperatorMetadata = {\n    name: Operators.NotArray,\n    displayName: \"Is Not Array\",\n    category: OperatorCategory.TYPE,\n    description: \"Checks if the field value is not an array\",\n    acceptedFieldTypes: [\"any\"],\n    expectedValueType: \"void\",\n    requiresValue: false,\n    isNegatable: false,\n    example: '{ field: \"data\", operator: \"not-array\" }',\n  };\n\n  private arrayOperator = new ArrayOperator();\n\n  evaluate(context: OperatorContext): boolean {\n    return !this.arrayOperator.evaluate(context);\n  }\n}\n"
  },
  {
    "path": "packages/core/src/operators/index.ts",
    "content": "import {\n  isValidTime,\n  isObject,\n  dateWithTzOffset,\n  convertTimeToMs,\n} from \"@root/utils\";\nimport { isBefore, isAfter } from \"date-fns\";\n\n/**\n * Checks if the value is equal to the compareValue. Both values must be of the same type. If the values are objects, it will compare the stringifies versions of the objects.\n * @param value\n * @param compareValue\n * @returns boolean\n * @example\n * equalsOperator(1, 1) // true\n * equalsOperator(1, 2) // false\n * equalsOperator('a', 'a') // true\n * equalsOperator('a', 'b') // false\n * equalsOperator(1, '1') // false\n * equalsOperator({ a: 1 }, { a: 1 }) // true\n * equalsOperator({ a: 1 }, { a: 2 }) // false\n * equalsOperator({ a: 1 }, { b: 1 }) // false\n * equalsOperator({ a: 1 }, { a: '1' }) // false\n * equalsOperator({ a: 1 }, { a: 1, b: 2 }) // false\n * equalsOperator(null, 1) // false\n * equalsOperator(1, null) // false\n * equalsOperator(undefined, 1) // false\n * equalsOperator(1, undefined) // false\n */\nexport function equalsOperator(value: any, compareValue: any): boolean {\n  if (value === undefined || compareValue === undefined) return false;\n  if (value === null || compareValue === null) return false;\n  if (typeof value !== typeof compareValue) return false;\n  if (value instanceof Date && compareValue instanceof Date)\n    return value.getTime() === compareValue.getTime();\n  if (\n    (isObject(value) && isObject(compareValue)) ||\n    (Array.isArray(value) && Array.isArray(compareValue))\n  )\n    return JSON.stringify(value) === JSON.stringify(compareValue);\n\n  return value === compareValue;\n}\n\n/**\n * Checks if the value is less than the compareValue. Both values must be of the same type.\n * @param value\n * @param compareValue\n * @returns boolean\n * @example\n * lessThanOperator(1, 2) // true\n * lessThanOperator(2, 1) // false\n * lessThanOperator('a', 'b') // true\n * lessThanOperator('b', 'a') // false\n * lessThanOperator(1, 'a') // false\n * lessThanOperator('a', 1) // false\n * lessThanOperator(null, 1) // false\n * lessThanOperator(1, null) // false\n * lessThanOperator(undefined, 1) // false\n * lessThanOperator(1, undefined) // false\n */\nexport function greaterThanOperator(value: any, compareValue: any): boolean {\n  if (value === undefined || compareValue === undefined) return false;\n  if (value === null || compareValue === null) return false;\n  if (typeof value !== typeof compareValue) return false;\n\n  return value > compareValue;\n}\n\n/**\n * Checks if the value is greater than the compareValue. Both values must be of the same type.\n * @param value\n * @param compareValue\n */\nexport function greaterThanOrEqualsOperator(\n  value: any,\n  compareValue: any,\n): boolean {\n  return (\n    equalsOperator(value, compareValue) ||\n    greaterThanOperator(value, compareValue)\n  );\n}\n\n/**\n * Checks if the value is less than the compareValue. Both values must be of the same type.\n * @param value\n * @param compareValue\n */\nexport function lessThanOperator(value: any, compareValue: any): boolean {\n  if (value === undefined || compareValue === undefined) return false;\n  if (value === null || compareValue === null) return false;\n  if (typeof value !== typeof compareValue) return false;\n\n  return value < compareValue;\n}\n\n/**\n * Checks if the value is less than or equal to the compareValue. Both values must be of the same type.\n * @param value\n * @param compareValue\n */\nexport function lessThanOrEqualsOperator(\n  value: any,\n  compareValue: any,\n): boolean {\n  return (\n    equalsOperator(value, compareValue) || lessThanOperator(value, compareValue)\n  );\n}\n\n/**\n * Parses and evaluates a safe and comprehensive SQL WHERE LIKE filter expression.\n *\n * @param text The text string to search (string).\n * @param pattern The pattern to match (string).\n * @param caseInsensitive (optional) A boolean flag indicating case-insensitive matching (default: false).\n * @returns boolean True if the text matches the pattern, False otherwise.\n * @example\n * likeOperator(\"Hello, World!\", \"Hello, World!\") // true\n * likeOperator(\"Hello, World!\", \"Hello, %\") // true\n * likeOperator(\"Hello, World!\", \"%World!\") // true\n * likeOperator(\"Hello, World!\", \"%World\") // false\n * likeOperator(\"Hello, World!\", \"Hello, %!\", true) // true\n * likeOperator(\"Hello, World!\", \"hello, %\", true) // true\n * likeOperator(\"Hello, World!\", \"Hello, %\", true) // false\n * // startsWith\n * likeOperator(\"Hello, World!\", \"^Hello, World!\") // true\n * likeOperator(\"Hello, World!\", \"^Hello, %\") // true\n * likeOperator(\"Hello, World!\", \"^Hello, World!\") // false\n * // endsWith\n * likeOperator(\"Hello, World!\", \"Hello, World!$\") // true\n * likeOperator(\"Hello, World!\", \"%World!$\") // true\n * likeOperator(\"Hello, World!\", \"Hello, World!$\") // false\n * // startsWith and endsWith\n * likeOperator(\"Hello, World!\", \"^Hello, World!$\") // true\n * likeOperator(\"Hello, World!\", \"^Hello, %$\") // true\n * likeOperator(\"Hello, World!\", \"^Hello, World!$\") // false\n */\nexport function likeOperator(\n  text: string,\n  pattern: string,\n  caseInsensitive = false,\n) {\n  // Escape special characters in the pattern to prevent SQL injection\n\n  const escapedPattern = pattern.replace(/([\\\\%_[\\]^$!@#&?()-='\">{}])/g, \"$1\");\n\n  // Build the regular expression with pattern handling\n  let regexStr = \"^\";\n  let isStartsWith = false;\n  let isEndsWith = false;\n\n  for (let i = 0; i < escapedPattern.length; i++) {\n    const char = escapedPattern[i];\n    switch (char) {\n      case \"%\":\n        regexStr += \".*\";\n        break;\n      case \"_\":\n        regexStr += \".\";\n        break;\n      case \"*\":\n        if (i === 0) {\n          isStartsWith = true; // Starts with\n        } else if (i === escapedPattern.length - 1) {\n          isEndsWith = true; // Ends with\n        } else {\n          // Invalid wildcard placement\n          return false;\n        }\n        break;\n      case \"[\": {\n        // Character set handling\n        let charSetStr = \"\";\n        let isNegated = false;\n        if (escapedPattern[i + 1] === \"^\") {\n          isNegated = true;\n          i++; // Skip leading negation character\n        }\n        for (let j = i + 1; j < escapedPattern.length; j++) {\n          if (escapedPattern[j] === \"]\") {\n            i = j; // Update loop index\n            break;\n          }\n          charSetStr += escapedPattern[j];\n        }\n        regexStr += isNegated ? `[^${charSetStr}]` : `[${charSetStr}]`;\n        break;\n      }\n      case \"^\": // Starts with\n        if (i === 0) {\n          isStartsWith = true;\n        } else {\n          // Invalid placement of \"^\"\n          return false;\n        }\n        break;\n      case \"$\": // Ends with\n        if (i === escapedPattern.length - 1) {\n          isEndsWith = true;\n        } else {\n          // Invalid placement of \"$\"\n          return false;\n        }\n        break;\n      case \"!\": // Escape following character (literal match)\n        if (i + 1 < escapedPattern.length) {\n          regexStr += escapedPattern[i + 1];\n          i++; // Skip the escaped character\n        } else {\n          // Invalid escape at the end\n          return false;\n        }\n        break;\n      default:\n        regexStr += char;\n    }\n  }\n\n  // Add anchors based on startsWith and endsWith\n  // if (isStartsWith) {\n  //   regexStr = regexStr.substring(0, 1); // Remove leading ^\n  // }\n  if (isEndsWith) {\n    regexStr += \"$\"; // Add trailing $\n  } else if (!isStartsWith) {\n    regexStr += \"$\"; // Add trailing $ for default full match\n  }\n\n  // Build and test the regular expression\n  return new RegExp(regexStr, caseInsensitive ? \"i\" : undefined).test(text);\n}\n\nexport function isNullOrWhiteSpaceOperator(value: string): boolean {\n  return value === null || value === undefined || value.trim() === \"\";\n}\n\nexport function isNumericOperator(value: any): boolean {\n  return !Number.isNaN(Number(value));\n}\n\nexport function isBooleanOperator(value: any): boolean {\n  return typeof value === \"boolean\";\n}\n\nexport function isDateOperator(value: any): boolean {\n  try {\n    return new Date(value).toString() !== \"Invalid Date\";\n  } catch {\n    return false;\n  }\n}\n\nexport function isEmailOperator(value: string): boolean {\n  const emailRegex = /^[^\\s@]+@[^\\s@][^\\s.@]*\\.[^\\s@]+$/;\n  return emailRegex.test(value);\n}\n\nexport function isUrlOperator(value: string): boolean {\n  try {\n    new URL(value);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nexport function isUuidOperator(value: string): boolean {\n  const uuidRegex =\n    /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;\n  return uuidRegex.test(value);\n}\n\nexport const faAlphabet = \"ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهی\";\nexport const faNumber = \"۰۱۲۳۴۵۶۷۸۹\";\nexport const faShortVowels = \"َُِ\";\nexport const faOthers = \"‌آاً\";\nexport const faMixedWithArabic = \"ًٌٍَُِّْٰٔءك‌ةۀأإيـئؤ،\";\nexport const faText = faAlphabet + faNumber + faShortVowels + faOthers;\nexport const faAlphaText = faAlphabet + faShortVowels + faOthers;\nexport const faComplexText = faText + faMixedWithArabic;\nexport const faAlphaComplexText = faAlphaText + faMixedWithArabic;\nexport function isAlphaOperator(value: string): boolean {\n  const alphaRegex = /^[a-z]+$/i;\n  return alphaRegex.test(value);\n}\nexport function isPersianAlphaOperator(value: string): boolean {\n  const text = value.replace(/[\"'-+؟\\s.]/g, \"\");\n\n  return new RegExp(`^[${faAlphaText}]+$`).test(text);\n}\n\nexport function isAlphaNumericOperator(value: string): boolean {\n  const alphaNumericRegex = /^[a-z0-9]+$/i;\n  return alphaNumericRegex.test(value);\n}\n\nexport function isPersianAlphaNumericOperator(value: string): boolean {\n  const text = value.replace(/[\"'-+؟\\s.]/g, \"\");\n\n  return new RegExp(`^[${faComplexText}]+$`).test(text);\n}\n\nexport function isLowerCaseOperator(value: string): boolean {\n  return value === value.toLowerCase();\n}\n\nexport function isUpperCaseOperator(value: string): boolean {\n  return value === value.toUpperCase();\n}\n\nexport function isStringOperator(value: any): boolean {\n  return typeof value === \"string\";\n}\n\nexport function isObjectOperator(value: any): boolean {\n  return isObject(value);\n}\n\nexport function isArrayOperator(value: any): boolean {\n  return Array.isArray(value);\n}\n\nexport function isBooleanStringOperator(value: string): boolean {\n  return value === \"true\" || value === \"false\";\n}\n\nexport function isBooleanNumberOperator(value: any): boolean {\n  return value === 0 || value === 1;\n}\n\nexport function isBooleanNumberStringOperator(value: any): boolean {\n  return value === \"0\" || value === \"1\";\n}\n\nexport function isNumberOperator(value: any): boolean {\n  // Check if it's a number using typeof\n  if (typeof value === \"number\") {\n    // Check for NaN (Not a Number)\n    return !Number.isNaN(value);\n  }\n\n  // Check if it's a string and can be converted to a number\n  if (typeof value === \"string\") {\n    const num = Number(value);\n    return !Number.isNaN(num) && value.trim() !== \"\";\n  }\n\n  return false;\n}\n\nexport function isIntegerOperator(value: any): boolean {\n  if (!isNumberOperator(value)) return false;\n\n  return value === Number.parseInt(value, 10);\n}\n\nexport function isFloatOperator(value: any): boolean {\n  if (!isNumericOperator(value)) return false;\n\n  const epsilon = Number.EPSILON; // Machine epsilon for floating-point precision\n  return (\n    Number.isFinite(value) && Math.abs(value - Math.floor(value)) > epsilon\n  );\n}\n\nexport function isPositiveOperator(value: any): boolean {\n  if (!isNumericOperator(value)) return false;\n\n  return value > 0;\n}\n\nexport function isNegativeOperator(value: any): boolean {\n  if (!isNumericOperator(value)) return false;\n\n  return value < 0;\n}\n\nexport function isZeroOperator(value: any): boolean {\n  if (!isNumericOperator(value)) return false;\n\n  return Number(value) === 0;\n}\n\nexport function isNumberBetweenOperator(\n  value: any,\n  compareValues: any[],\n): boolean {\n  if (!Array.isArray(compareValues) || compareValues.length !== 2) return false;\n  if (!isNumericOperator(value)) return false;\n\n  const [start, end] = compareValues;\n  return value >= Number(start) && value <= Number(end);\n}\n\nexport function isLengthOperator(value: any, compareValue: any): boolean {\n  if (!isStringOperator(value)) return false;\n  if (!isNumericOperator(compareValue)) return false;\n\n  return value.length === compareValue;\n}\n\nexport function isMinLengthOperator(value: any, compareValue: any): boolean {\n  if (!isStringOperator(value)) return false;\n  if (!isNumericOperator(compareValue)) return false;\n\n  return value.length >= compareValue;\n}\n\nexport function isMaxLengthOperator(value: any, compareValue: any): boolean {\n  if (!isStringOperator(value)) return false;\n  if (!isNumericOperator(compareValue)) return false;\n\n  return value.length <= compareValue;\n}\n\nexport function IsLengthBetweenOperator(\n  value: any,\n  compareValues: any[],\n): boolean {\n  if (typeof value !== \"string\") return false;\n  if (!Array.isArray(compareValues) || compareValues.length !== 2) return false;\n\n  const [min, max] = compareValues;\n  return value.length >= Number(min) && value.length <= Number(max);\n}\n\nexport function isMinOperator(value: any, compareValue: any): boolean {\n  if (!isNumericOperator(value)) return false;\n  if (!isNumericOperator(compareValue)) return false;\n\n  return value >= compareValue;\n}\n\nexport function isMaxOperator(value: any, compareValue: any): boolean {\n  return value <= compareValue;\n}\n\nexport function isBetweenOperator(value: any, compareValues: any[]): boolean {\n  if (!Array.isArray(compareValues) || compareValues.length !== 2) return false;\n  if (!isNumericOperator(value)) return false;\n\n  const [min, max] = compareValues;\n  return value >= Number(min) && value <= Number(max);\n}\n\nexport function isFalsyOperator(value: any): boolean {\n  // Standard JavaScript falsy values: false, 0, -0, 0n, \"\", null, undefined, NaN\n  return (\n    (!value && value !== 0 && value !== false && value !== \"\") ||\n    value === 0 ||\n    value === false ||\n    value === \"\" ||\n    value === null ||\n    value === undefined ||\n    Number.isNaN(value)\n  );\n}\n\nexport function isTruthyOperator(value: any): boolean {\n  // Returns true for any truthy value in JavaScript\n  return !!value;\n}\n\n/**\n * Checks if the value is not equal to the compareValue. Both values must be of the same type.\n * @param value\n * @param compareValues\n * @constructor\n */\nexport function inOperator(value: any, compareValues: any[]): boolean {\n  if (!Array.isArray(compareValues)) return false;\n\n  return compareValues.includes(value);\n}\n\nexport function containsOperator(value: any, compareValue: any): boolean {\n  if (!Array.isArray(value)) return false;\n\n  return value.includes(compareValue);\n}\n\nexport function selfContainsAllOperator(\n  value: any,\n  compareValues: any[],\n): boolean {\n  if (!isStringOperator(value) || !Array.isArray(compareValues)) return false;\n\n  return compareValues.every((compareValue) => value.includes(compareValue));\n}\n\nexport function selfContainsAnyOperator(\n  value: any,\n  compareValues: any[],\n): boolean {\n  if (!isStringOperator(value) || !Array.isArray(compareValues)) return false;\n\n  return compareValues.some((compareValue) => value.includes(compareValue));\n}\n\nexport function selfContainsNoneOperator(\n  value: any,\n  compareValues: any[],\n): boolean {\n  if (!isStringOperator(value) || !Array.isArray(compareValues)) return false;\n\n  return compareValues.every((compareValue) => !value.includes(compareValue));\n}\n\nexport function containsAnyOperator(value: any, compareValues: any[]): boolean {\n  if (!Array.isArray(value) || !Array.isArray(compareValues)) return false;\n\n  return value.some((compareValue) => compareValues.includes(compareValue));\n}\n\nexport function containsAllOperator(value: any, compareValues: any[]): boolean {\n  if (!Array.isArray(value) || !Array.isArray(compareValues)) return false;\n\n  return compareValues.every((compareValue) => value.includes(compareValue));\n}\n\nexport function matchesOperator(value: string, pattern: string): boolean {\n  if (!isStringOperator(value) || !isStringOperator(pattern)) return false;\n  if (pattern.length === 0) return false;\n\n  if (pattern.startsWith(\"/\") && pattern.endsWith(\"/\")) {\n    pattern = pattern.slice(1, -1);\n  }\n  return new RegExp(pattern).test(value);\n}\n\nexport function isExistsInObjectOperator(key: any, obj: any): boolean {\n  if (!isObject(obj)) return false;\n\n  return key in obj;\n}\n\nexport function isNullOrUndefinedOperator(value: any): boolean {\n  return value === null || value === undefined;\n}\n\nexport function isEmptyOperator(value: any): boolean {\n  if (Array.isArray(value)) return value.length === 0;\n  if (isObject(value)) return Object.keys(value).length === 0;\n  if (typeof value === \"string\") return value === \"\";\n\n  return false;\n}\n\nexport function isDateAfterOperator(left: any, right: any): boolean {\n  try {\n    return (\n      left !== right &&\n      isAfter(\n        dateWithTzOffset(new Date(left)),\n        dateWithTzOffset(new Date(right)),\n      )\n    );\n  } catch {\n    return false;\n  }\n}\n\nexport function isDateAfterNowOperator(value: any): boolean {\n  try {\n    return isAfter(dateWithTzOffset(new Date(value)), new Date());\n  } catch {\n    return false;\n  }\n}\n\nexport function isDateBeforeOperator(left: any, right: any): boolean {\n  try {\n    return (\n      left !== right &&\n      isBefore(\n        dateWithTzOffset(new Date(left)),\n        dateWithTzOffset(new Date(right)),\n      )\n    );\n  } catch {\n    return false;\n  }\n}\n\nexport function isDateBeforeNowOperator(value: any): boolean {\n  try {\n    return isBefore(dateWithTzOffset(new Date(value)), new Date());\n  } catch {\n    return false;\n  }\n}\n\nexport function isDateAfterOrEqualsOperator(left: any, right: any): boolean {\n  try {\n    return !isBefore(\n      dateWithTzOffset(new Date(left)),\n      dateWithTzOffset(new Date(right)),\n    );\n  } catch {\n    return false;\n  }\n}\n\nexport function isDateAfterNowOrEqualsOperator(value: any): boolean {\n  try {\n    return !isBefore(dateWithTzOffset(new Date(value)), new Date());\n  } catch {\n    return false;\n  }\n}\n\nexport function isDateBeforeOrEqualsOperator(left: any, right: any): boolean {\n  try {\n    return !isAfter(\n      dateWithTzOffset(new Date(left)),\n      dateWithTzOffset(new Date(right)),\n    );\n  } catch {\n    return false;\n  }\n}\n\nexport function isDateBeforeNowOrEqualsOperator(value: any): boolean {\n  try {\n    return !isAfter(dateWithTzOffset(new Date(value)), new Date());\n  } catch {\n    return false;\n  }\n}\n\nexport function isDateEqualsOperator(left: any, right: any): boolean {\n  try {\n    return (\n      dateWithTzOffset(new Date(left)).getTime() ===\n      dateWithTzOffset(new Date(right)).getTime()\n    );\n  } catch {\n    return false;\n  }\n}\n\nexport function isDateEqualsToNowOperator(dateValue: any): boolean {\n  try {\n    return (\n      dateWithTzOffset(new Date(dateValue)).getTime() === new Date().getTime()\n    );\n  } catch {\n    return false;\n  }\n}\n\nexport function isDateBetweenOperator(left: any, rightRange: any[]): boolean {\n  try {\n    if (!Array.isArray(rightRange) || rightRange.length !== 2) return false;\n\n    const [start, end] = rightRange;\n    return (\n      isAfter(\n        dateWithTzOffset(new Date(left)),\n        dateWithTzOffset(new Date(start)),\n      ) &&\n      isBefore(\n        dateWithTzOffset(new Date(left)),\n        dateWithTzOffset(new Date(end)),\n      )\n    );\n  } catch {\n    return false;\n  }\n}\n\nexport function isTimeAfterOperator(left: any, right: any): boolean {\n  try {\n    return convertTimeToMs(left) > convertTimeToMs(right);\n  } catch {\n    return false;\n  }\n}\n\nexport function isTimeBeforeOperator(left: any, right: any): boolean {\n  try {\n    return convertTimeToMs(left) < convertTimeToMs(right);\n  } catch {\n    return false;\n  }\n}\n\nexport function isTimeAfterOrEqualsOperator(left: any, right: any): boolean {\n  try {\n    return convertTimeToMs(left) >= convertTimeToMs(right);\n  } catch {\n    return false;\n  }\n}\n\nexport function isTimeBeforeOrEqualsOperator(left: any, right: any): boolean {\n  try {\n    return convertTimeToMs(left) <= convertTimeToMs(right);\n  } catch {\n    return false;\n  }\n}\n\nexport function isTimeEqualsOperator(left: any, right: any): boolean {\n  try {\n    return convertTimeToMs(left) === convertTimeToMs(right);\n  } catch {\n    return false;\n  }\n}\n\nexport function isTimeBetweenOperator(left: any, right: any[]): boolean {\n  if (!Array.isArray(right) || right.length !== 2) return false;\n  if (!isValidTime(left)) return false;\n\n  const [start, end] = right;\n  return isTimeAfterOperator(left, start) && isTimeBeforeOperator(left, end);\n}\n"
  },
  {
    "path": "packages/core/src/operators/like.md",
    "content": "# Like Operator\nIt provides a safe and expressive way to parse and evaluate SQL WHERE LIKE filter expressions with wildcards (%, _), startsWith, and endsWith capabilities. It prioritizes security by escaping special characters to prevent SQL injection vulnerabilities.\n\n### Function Parameters\n\n- `text` (string): The text string to search for.\n- `pattern` (string): The filter expression pattern to match against.\n\n### Return Value\n\n- `boolean`: Returns true if the text matches the pattern, false otherwise.\n\n### Supported Wildcards and Features\n\n- `%`: Matches any sequence of characters (zero or more times).\n- `_`: Matches any single character.\n- `*`:\n  - Placed at the beginning of the pattern: Matches strings that start with the characters following *. (startsWith)\n  - Placed at the end of the pattern: Matches strings that end with the characters preceding *. (endsWith)\n  - Any other placement of * is considered invalid and will return false.\n  \n### Example Usage\n\n- `Basic` Matching:\n```typeScript\nconst text1 = \"This is an example string\";\nconst pattern1 = \"Th%s is an exa%le str%g\"; // Matches\nconsole.log(safeSqlLikeEnhanced(text1, pattern1)); // Output: true\n```\n- `Not` Matching:\n```typeScript\nconst text2 = \"This is a different string\";\nconst pattern2 = \"%manager%\"; // Doesn't match\nconsole.log(safeSqlLikeEnhanced(text2, pattern2)); // Output: false\n```\n- `StartsWith` Matching:\n```typeScript\nconst text3 = \"Starting string\";\nconst pattern3 = \"*ing string\"; // Starts with \"ing\"\nconsole.log(safeSqlLikeEnhanced(text3, pattern3)); // Output: true\n```\n- `EndsWith` Matching:\n```typeScript\nconst text4 = \"Ending string\";\nconst pattern4 = \"Ending*\"; // Ends with \"ing\"\nconsole.log(safeSqlLikeEnhanced(text4, pattern4)); // Output: true\n```\n- `Invalid` Wildcard Placement:\n```typeScript\nconst text5 = \"Invalid*placement\";\nconst pattern5 = \"In*val*id\"; // Invalid placement of \"*\"\nconsole.log(safeSqlLikeEnhanced(text5, pattern5)); // Output: false\n```\n\n### Constraints\n- The function should handle special characters and escape sequences correctly.\n- The function should return false for invalid wildcard placements.\n- The function should return true for valid wildcard placements and matching patterns.\n- The function should return false for valid wildcard placements and non-matching patterns.\n\n### Use Cases\n1. Matching strings with specific lengths:\n   - Example: `pattern = \"abc_de_%\"`\n   - Explanation: This pattern matches strings that start with \"abc\", followed by an underscore, then any single character, another underscore, and finally any sequence of characters (zero or more times). This would match strings like \"abc_x_defg\", \"abc_y_123\", etc., but not \"abc_def\" (too short) or \"abc_defg\" (no trailing characters allowed).\n   - Example:\n     - `text = \"abc_x_defg\"` => `pattern = \"abc_de_%\"` => `true`\n     - `text = \"abc_y_123\"` => `pattern = \"abc_de_%\"` => `true`\n     - `text = \"abc_def\"` => `pattern = \"abc_de_%\"` => `false`\n     - `text = \"abc_defg\"` => `pattern = \"abc_de_%\"` => `false`\n     - `text = \"abc_x_defg\"` => `pattern = \"abc_de_%g\"` => `true`\n     - `text = \"abc_y_123\"` => `pattern = \"abc_de_%g\"` => `false`\n2. Matching a range of characters within a set:\n   - Example: `pattern = \"[a-c]_%\"`\n   - Explanation: This pattern matches strings that start with a character between 'a' and 'c' (inclusive), followed by an underscore, and then any sequence of characters (zero or more times). This would match strings like \"a_def\", \"b_ghi\", \"c_jkl\", but not \"d_mno\" (character outside the range).\n   - Example:\n     - `text = \"a_def\"` => `pattern = \"[a-c]_%\"` => `true`\n     - `text = \"b_ghi\"` => `pattern = \"[a-c]_%\"` => `true`\n     - `text = \"c_jkl\"` => `pattern = \"[a-c]_%\"` => `true`\n     - `text = \"d_mno\"` => `pattern = \"[a-c]_%\"` => `false`\n3. Negation within a character set:\n   - Example: `pattern = \"[^aeiou]_%\"`\n   - Explanation: This pattern matches strings that start with a character that is not a vowel (a, e, i, o, u), followed by an underscore, and then any sequence of characters (zero or more times). This would match strings like \"x_def\", \"z_ghi\", but not \"a_jkl\" (vowel) or \"e_mno\" (vowel).\n   - Example:\n     - `text = \"x_def\"` => `pattern = \"[^aeiou]_%\"` => `true`\n     - `text = \"z_ghi\"` => `pattern = \"[^aeiou]_%\"` => `true`\n     - `text = \"a_jkl\"` => `pattern = \"[^aeiou]_%\"` => `false`\n     - `text = \"e_mno\"` => `pattern = \"[^aeiou]_%\"` => `false`\n4. Combining features with wildcards and escapes:\n   - Example: `pattern = \"Th\\%is is an exa\\%ple str%ng\"`\n   - Explanation: This pattern matches strings that are an exact match for \"This is an example string\", but with escaped percentage signs (`\\%`) to treat them literally. This is useful when you want to search for literal percentages in the text.\n   - Note: The backslash (`\\`) is used to escape special characters, treating them as literals.\n   - Example:\n     - `text = \"This is an example string\"` => `pattern = \"Th\\%is is an exa\\%ple str%ng\"` => `true`\n     - `text = \"This is an example string\"` => `pattern = \"Th\\%is is an exa%ple str%ng\"` => `false`\n     - `text = \"This is an example string\"` => `pattern = \"Th\\%is is an exa\\%ple str%ng\"` => `false`\n5. Matching filenames with specific extensions:\n   - Example: `pattern = \"%.txt\"` (assuming extensions are separated by a dot)\n   - Explanation: This pattern matches strings that end with \".txt\" (case-sensitive). This would match filenames like \"myfile.txt\", \"document.txt\", but not \"image.jpg\" (different extension).\n   - Note: The percent sign (`%`) matches any sequence of characters (zero or more times), allowing for flexible matching of filenames with different prefixes.\n   - Example:\n     - `text = \"myfile.txt\"` => `pattern = \"%.txt\"` => `true`\n     - `text = \"document.txt\"` => `pattern = \"%.txt\"` => `true`\n     - `text = \"image.jpg\"` => `pattern = \"%.txt\"` => `false`\n     - `text = \"myfile.txt\"` => `pattern = \"myfile.%\"` => `false`\n     - `text = \"myfile.txt\"` => `pattern = \"myfile.txt%\"` => `false`\n     - `text = \"myfile.txt\"` => `pattern = \"myfile.txt\"` => `true`\n\n### Important Notes\n- This function prioritizes security by escaping special characters (\\, %, ., _) in the pattern to prevent SQL injection vulnerabilities.\n- While it offers a safe approach, consider using prepared statements or parameterized queries in production environments for maximum security.\n- The underscore (`_`) wildcard matches any single character.\n- The percent sign (`%`) matches any sequence of characters (zero or more times).\n- The square brackets (`[]`) denote a character set, allowing you to specify a range of characters or individual characters to match.\n- The hyphen (`-`) inside a character set denotes a range of characters.\n- The caret (`^`) symbol at the beginning of a character set negates the set, matching any character not in the set.\n- The backslash (`\\`) is used to escape special characters, treating them as literals.\n- The asterisk (`*`) is used to denote startsWith and endsWith capabilities in the pattern.\n- This function is designed to be used in a safe and controlled environment to evaluate SQL LIKE filter expressions.\n- The function is case-sensitive by default, but you can modify it to be case-insensitive if needed.\n- The function is designed to work with standard SQL LIKE patterns and may require modifications for specific database implementations.\n- The function is intended for use in backend applications where SQL queries are constructed dynamically based on user input or other criteria.\n- The function is written in TypeScript, but it can be easily adapted to other programming languages like JavaScript.\n\n### Additional Considerations \n- This implementation can be extended to support more complex patterns and escape characters if needed.\n- Error handling could be further improved to provide more informative messages for invalid patterns.\n"
  },
  {
    "path": "packages/core/src/operators/registry.ts",
    "content": "import { Operators } from \"@root/enums\";\nimport type { OperatorsType } from \"@root/types\";\nimport type {\n  OperatorStrategy,\n  OperatorMetadata,\n  OperatorFactory,\n  OperatorConstructor,\n  OperatorCategory,\n} from \"./base\";\n\n/**\n * Registry for managing operators\n */\nexport class OperatorRegistry {\n  private static instance: OperatorRegistry;\n  private operators: Map<OperatorsType, OperatorFactory> = new Map();\n  private metadata: Map<OperatorsType, OperatorMetadata> = new Map();\n  private initialized = false;\n\n  private constructor() {\n    // Private constructor for singleton\n  }\n\n  /**\n   * Get singleton instance\n   */\n  static getInstance(): OperatorRegistry {\n    if (!OperatorRegistry.instance) {\n      OperatorRegistry.instance = new OperatorRegistry();\n    }\n    return OperatorRegistry.instance;\n  }\n\n  /**\n   * Register a new operator\n   * @param operator The operator class or factory function\n   * @param override Whether to override existing operator\n   */\n  register(\n    operator: OperatorConstructor | OperatorFactory,\n    override = false,\n  ): void {\n    // Create instance to get metadata\n    const instance = this.createInstance(operator);\n    const { name } = instance.metadata;\n\n    if (this.operators.has(name) && !override) {\n      throw new Error(\n        `Operator \"${name}\" is already registered. Use override=true to replace.`,\n      );\n    }\n\n    // Store factory function\n    const factory =\n      typeof operator === \"function\" && operator.prototype\n        ? () => new (operator as OperatorConstructor)()\n        : (operator as OperatorFactory);\n\n    this.operators.set(name, factory);\n    this.metadata.set(name, instance.metadata);\n  }\n\n  /**\n   * Register multiple operators at once\n   * @param operators Array of operator classes or factories\n   * @param override Whether to override existing operators\n   */\n  registerMany(\n    operators: Array<OperatorConstructor | OperatorFactory>,\n    override = false,\n  ): void {\n    for (const operator of operators) {\n      this.register(operator, override);\n    }\n  }\n\n  /**\n   * Unregister an operator\n   * @param name The operator name\n   */\n  unregister(name: OperatorsType): boolean {\n    const deleted = this.operators.delete(name);\n    this.metadata.delete(name);\n    return deleted;\n  }\n\n  /**\n   * Get an operator instance by name\n   * @param name The operator name\n   * @returns The operator instance or null\n   */\n  get(name: OperatorsType): OperatorStrategy | null {\n    const factory = this.operators.get(name);\n    return factory ? factory() : null;\n  }\n\n  /**\n   * Check if an operator is registered\n   * @param name The operator name\n   */\n  has(name: OperatorsType): boolean {\n    return this.operators.has(name);\n  }\n\n  /**\n   * Get all registered operator names\n   */\n  getOperatorNames(): OperatorsType[] {\n    return Array.from(this.operators.keys());\n  }\n\n  /**\n   * Get all operator metadata\n   */\n  getAllMetadata(): OperatorMetadata[] {\n    return Array.from(this.metadata.values());\n  }\n\n  /**\n   * Get operators by category\n   * @param category The operator category\n   */\n  getByCategory(category: OperatorCategory): OperatorMetadata[] {\n    return this.getAllMetadata().filter((meta) => meta.category === category);\n  }\n\n  /**\n   * Get operators that accept a specific field type\n   * @param fieldType The field type\n   */\n  getByFieldType(fieldType: string): OperatorMetadata[] {\n    return this.getAllMetadata().filter((meta) =>\n      meta.acceptedFieldTypes.includes(fieldType as any),\n    );\n  }\n\n  /**\n   * Clear all registered operators\n   */\n  clear(): void {\n    this.operators.clear();\n    this.metadata.clear();\n    this.initialized = false;\n  }\n\n  /**\n   * Check if operators have been initialized\n   */\n  isInitialized(): boolean {\n    return this.initialized;\n  }\n\n  /**\n   * Mark as initialized\n   */\n  markInitialized(): void {\n    this.initialized = true;\n  }\n\n  /**\n   * Get negated operator for a given operator\n   * @param name The operator name\n   * @returns The negated operator name or null\n   */\n  getNegatedOperator(name: OperatorsType): OperatorsType | null {\n    // Map of operators to their negated versions\n    const negationMap: Partial<Record<OperatorsType, OperatorsType>> = {\n      [Operators.Equals]: Operators.NotEquals,\n      [Operators.NotEquals]: Operators.Equals,\n      [Operators.Like]: Operators.NotLike,\n      [Operators.NotLike]: Operators.Like,\n      [Operators.GreaterThan]: Operators.LessThanOrEquals,\n      [Operators.LessThan]: Operators.GreaterThanOrEquals,\n      [Operators.GreaterThanOrEquals]: Operators.LessThan,\n      [Operators.LessThanOrEquals]: Operators.GreaterThan,\n      [Operators.In]: Operators.NotIn,\n      [Operators.NotIn]: Operators.In,\n      [Operators.Contains]: Operators.NotContains,\n      [Operators.NotContains]: Operators.Contains,\n      [Operators.ContainsAny]: Operators.NotContainsAny,\n      [Operators.NotContainsAny]: Operators.ContainsAny,\n      [Operators.ContainsAll]: Operators.NotContainsAll,\n      [Operators.NotContainsAll]: Operators.ContainsAll,\n      [Operators.Matches]: Operators.NotMatches,\n      [Operators.NotMatches]: Operators.Matches,\n      [Operators.Exists]: Operators.NotExists,\n      [Operators.NotExists]: Operators.Exists,\n      [Operators.Empty]: Operators.NotEmpty,\n      [Operators.NotEmpty]: Operators.Empty,\n      [Operators.NullOrUndefined]: Operators.NotNullOrUndefined,\n      [Operators.NotNullOrUndefined]: Operators.NullOrUndefined,\n      [Operators.DateAfter]: Operators.DateBeforeOrEquals,\n      [Operators.DateBefore]: Operators.DateAfterOrEquals,\n      [Operators.DateAfterOrEquals]: Operators.DateBefore,\n      [Operators.DateBeforeOrEquals]: Operators.DateAfter,\n      [Operators.DateEquals]: Operators.DateNotEquals,\n      [Operators.DateNotEquals]: Operators.DateEquals,\n      [Operators.DateBetween]: Operators.DateNotBetween,\n      [Operators.DateNotBetween]: Operators.DateBetween,\n      [Operators.Boolean]: Operators.NotBoolean,\n      [Operators.NotBoolean]: Operators.Boolean,\n      [Operators.String]: Operators.NotString,\n      [Operators.NotString]: Operators.String,\n      [Operators.Number]: Operators.NotNumber,\n      [Operators.NotNumber]: Operators.Number,\n      [Operators.Array]: Operators.NotArray,\n      [Operators.NotArray]: Operators.Array,\n      [Operators.Object]: Operators.NotObject,\n      [Operators.NotObject]: Operators.Object,\n      // Add more mappings as needed\n    };\n\n    return negationMap[name] || null;\n  }\n\n  /**\n   * Create an instance from a constructor or factory\n   */\n  private createInstance(\n    operator: OperatorConstructor | OperatorFactory,\n  ): OperatorStrategy {\n    if (typeof operator === \"function\" && operator.prototype) {\n      return new (operator as OperatorConstructor)();\n    }\n    return (operator as OperatorFactory)();\n  }\n\n  /**\n   * Export registry data for introspection\n   */\n  export(): {\n    operators: Array<{\n      name: OperatorsType;\n      metadata: OperatorMetadata;\n    }>;\n  } {\n    return {\n      operators: Array.from(this.metadata.entries()).map(\n        ([name, metadata]) => ({\n          name,\n          metadata,\n        }),\n      ),\n    };\n  }\n\n  /**\n   * Import registry data (useful for testing or configuration)\n   */\n  import(data: {\n    operators: Array<{\n      name: OperatorsType;\n      factory: OperatorFactory;\n    }>;\n  }): void {\n    this.clear();\n    for (const { name, factory } of data.operators) {\n      const instance = factory();\n      this.operators.set(name, factory);\n      this.metadata.set(name, instance.metadata);\n    }\n  }\n}\n\n// Export singleton instance\nexport const operatorRegistry = OperatorRegistry.getInstance();\n"
  },
  {
    "path": "packages/core/src/services/builder.ts",
    "content": "import type { Validator } from \"@root/services/validator\";\n// Types\nimport type {\n  RuleType,\n  OperatorsType,\n  Constraint,\n  ConditionType,\n  Condition,\n} from \"@root/types\";\n\nexport class RuleBuilder<T = any> {\n  /** Stores to rule being constructed */\n  private rule: RuleType = { conditions: [] };\n\n  constructor(public readonly validator: Validator) {}\n\n  /**\n   * Adds a node (in the root) to the rule being constructed\n   *\n   * @param node The node to add to the rule\n   */\n  add(node: Condition<T>): RuleBuilder<T> {\n    (this.rule.conditions as Condition<T>[]).push(node);\n\n    return this;\n  }\n\n  /**\n   * Sets the default value of the rule being constructed\n   *\n   * @param value The default value of the rule\n   * @returns The builder instance\n   */\n  default(value: RuleType[\"default\"]): RuleBuilder<T> {\n    this.rule.default = value;\n\n    return this;\n  }\n\n  /**\n   * Builds the rule being and returns it (optionally validating it)\n   *\n   * @param validate Whether to validate the rule before returning it\n   * @returns The rule being constructed\n   * @throws Error if validation is enabled and the rule is invalid\n   */\n  build(validate?: boolean): RuleType<T> {\n    if (!validate) {\n      return this.rule;\n    }\n\n    const validationResult = this.validator.validate(this.rule);\n    if (validationResult.isValid) {\n      return this.rule;\n    }\n\n    throw validationResult;\n  }\n\n  /**\n   * Creates a new condition node for the rule being constructed\n   *\n   * @param type The type of condition\n   * @param nodes Any child nodes of the condition\n   * @param result The result of the condition node (for granular rules)\n   * @returns The condition node\n   */\n  condition(\n    type: ConditionType,\n    nodes: Condition<T>[ConditionType],\n    result?: Condition<T>[\"result\"],\n  ): Condition<T> {\n    return {\n      [type]: nodes,\n      result,\n    };\n  }\n\n  /**\n   * Creates a new constraint node for a condition node to use\n   *\n   * @param field The field to apply the constraint to\n   * @param operator The operator to apply to the field\n   * @param value The value to compare the field to\n   * @returns The constraint node\n   */\n  constraint(\n    field: string,\n    operator: OperatorsType,\n    value: Constraint[\"value\"],\n  ): Constraint {\n    return {\n      field,\n      operator,\n      value,\n    };\n  }\n}\n"
  },
  {
    "path": "packages/core/src/services/evaluator.ts",
    "content": "import { ObjectDiscovery } from \"@root/services/object-discovery\";\nimport { operatorRegistry } from \"@root/operators/registry\";\nimport { ConditionTypes } from \"@root/enums\";\nimport { isStringOperator } from \"@root/operators\";\nimport type {\n  RuleType,\n  EvaluationResult,\n  EngineResult,\n  CriteriaObject,\n  Criteria,\n  Constraint,\n  Condition,\n} from \"@root/types\";\nimport type { OperatorContext } from \"@root/operators/base\";\n\nexport class Evaluator<T = any> {\n  private readonly discovery = new ObjectDiscovery<T>();\n\n  /**\n   * Evaluates a rule against a single criteria object and returns a single result.\n   *\n   * @param rule The rule to evaluate.\n   * @param criteria The criteria object to evaluate the rule against.\n   * @returns {EvaluationResult} The result of the rule evaluation.\n   */\n  evaluate(rule: RuleType, criteria: CriteriaObject<T>): EvaluationResult<T>;\n\n  /**\n   * Evaluates a rule against an array of criteria and returns an array of results.\n   *\n   * @param rule The rule to evaluate.\n   * @param criteria The array of criteria to evaluate the rule against.\n   * @returns {Array<EvaluationResult>} An array of rule evaluation results.\n   */\n  evaluate(rule: RuleType, criteria: Array<T>): Array<EvaluationResult<T>>;\n\n  /**\n   * Evaluates a rule against a set of criteria and returns the result.\n   * If the criteria is an array (indicating multiple criteria to test),\n   * the rule will be evaluated against each item in the array and\n   * an array of results will be returned.\n   *\n   * @param rule The rule to evaluate.\n   * @param criteria The criteria to evaluate the rule against.\n   * @returns {EvaluationResult} The result of the rule evaluation.\n   */\n  evaluate(\n    rule: RuleType,\n    criteria: Criteria,\n  ): EvaluationResult<T> | Array<EvaluationResult<T>> {\n    // Cater for the case where the condition property is not an array.\n    const conditions = this.discovery.getConditions(rule);\n\n    if (Array.isArray(criteria)) {\n      const result: Array<EvaluationResult<T>> = [];\n      for (const $criteria of criteria) {\n        result.push(this.evaluateRule(conditions, $criteria, rule?.default));\n      }\n\n      return result;\n    }\n\n    return this.evaluateRule(conditions, criteria, rule?.default);\n  }\n\n  /**\n   * Evaluates a rule against a set of criteria and returns the result.\n   * If no conditions pass, the default result is returned.\n   * If no default result is provided, false is returned.\n   *\n   * @param conditions The conditions to evaluate.\n   * @param criteria The criteria to evaluate the conditions against.\n   * @param defaultResult The default result to return if no conditions pass.\n   * @returns {EvaluationResult} The result of the rule evaluation.\n   */\n  private evaluateRule(\n    conditions: Array<Condition<T>>,\n    criteria: Criteria,\n    defaultResult?: EngineResult<T>,\n  ): EvaluationResult<T> {\n    // We should evaluate all conditions and return the result\n    // of the first condition that passes.\n    let lastErrorMessage: string | undefined;\n\n    for (const condition of conditions) {\n      const evaluationResult = this.evaluateCondition(condition, criteria);\n      if (evaluationResult.isPassed) {\n        const message = (condition?.result as EvaluationResult)?.message;\n        return this.mutateResultMessage(\n          {\n            value: evaluationResult.value,\n            isPassed: evaluationResult.isPassed,\n            message,\n          },\n          criteria,\n          true,\n        );\n      }\n      // Don't return early on validation errors - continue evaluating other conditions\n      // Store the last error message to return if no conditions pass\n      if (evaluationResult.message) {\n        lastErrorMessage = evaluationResult.message;\n      }\n    }\n\n    const message =\n      lastErrorMessage || (defaultResult as EvaluationResult)?.message;\n    // If no conditions pass, we should return the default result of\n    // the rule or false if no default result is provided.\n    return this.mutateResultMessage(\n      {\n        value: defaultResult?.value as T,\n        isPassed: false,\n        message,\n      },\n      criteria,\n      false,\n    );\n  }\n\n  /**\n   * Evaluates a condition against a set of criteria and returns the result.\n   * Uses recursion to evaluate nested conditions.\n   * @param condition The condition to evaluate.\n   * @param criteria The criteria to evaluate the condition against.\n   */\n  private evaluateCondition(\n    condition: Condition<T>,\n    criteria: Criteria,\n  ): EvaluationResult<T> {\n    // The condition must have an 'any' or 'all' property.\n    const conditionType = this.discovery.conditionType(condition);\n    if (!conditionType) {\n      return {\n        value: false as T,\n        isPassed: false,\n        message: `Invalid condition type. Please provide a valid condition type. The condition type is case-sensitive.`,\n      };\n    }\n\n    // If the type is 'and' or 'none', we should set the initial\n    // result to true, otherwise we should set it to false.\n    let isPassed = [ConditionTypes.AND, ConditionTypes.NONE].includes(\n      conditionType,\n    );\n    // The result of the condition evaluation.\n    // Defaults to the initial value.\n    // This is used to store the result of the condition evaluation.\n    let value = isPassed as T;\n    // The result message. Defaults to an empty string. This is used to store the result message.\n    let message: string | undefined;\n\n    // Check each node in the condition.\n    processLoop: for (const node of condition[conditionType]!) {\n      const isCondition = this.discovery.isCondition(node);\n      const isConstraint = this.discovery.isConstraint(node);\n      value = isCondition\n        ? (node.result?.value as T)\n        : (condition.result?.value as T);\n\n      // Process the node based on its type.\n      // If the node is a condition, we should evaluate it.\n      // If it is a constraint, we should check it.\n      switch (conditionType) {\n        // If the condition type is 'or', we should return true if any of the conditions pass.\n        case ConditionTypes.OR: {\n          if (isCondition) {\n            const evaluation = this.evaluateCondition(node, criteria);\n            isPassed ||= evaluation.isPassed;\n          }\n          if (isConstraint) {\n            const evaluation = this.evaluateConstraint(node, criteria);\n            isPassed ||= evaluation.isPassed;\n\n            if (!evaluation.isPassed) {\n              message = evaluation.message;\n            } else {\n              break processLoop;\n            }\n          }\n          break;\n        }\n        // If the condition type is 'and', we should return true if all the conditions pass.\n        case ConditionTypes.AND: {\n          if (isCondition) {\n            const evaluation = this.evaluateCondition(node, criteria);\n            isPassed &&= evaluation.isPassed;\n\n            if (!evaluation.isPassed && evaluation.message) {\n              message = evaluation.message;\n\n              break processLoop;\n            }\n          }\n          if (isConstraint) {\n            const evaluation = this.evaluateConstraint(node, criteria);\n            isPassed &&= evaluation.isPassed;\n\n            if (!evaluation.isPassed) {\n              message = evaluation.message;\n\n              break processLoop;\n            }\n          }\n          break;\n        }\n        // If the condition type is 'none', we should return true if none of the conditions pass.\n        case ConditionTypes.NONE: {\n          if (isCondition) {\n            const evaluation = this.evaluateCondition(node, criteria);\n            isPassed &&= !evaluation.isPassed;\n          }\n          if (isConstraint) {\n            const evaluation = this.evaluateConstraint(node, criteria);\n            isPassed &&= !evaluation.isPassed;\n\n            if (!evaluation.isPassed) {\n              message = evaluation.message;\n            }\n          }\n          break;\n        }\n      }\n    }\n\n    return {\n      message,\n      value,\n      isPassed,\n    };\n  }\n\n  /**\n   * Checks a constraint against a set of criteria and returns true whenever the constraint passes. Otherwise, false is returned.\n   * Uses the Strategy pattern to evaluate operators.\n   *\n   * @param constraint The constraint to evaluate.\n   * @param criteria The criteria to evaluate the constraint with.\n   */\n  private evaluateConstraint(\n    constraint: Constraint,\n    criteria: Criteria,\n  ): EvaluationResult<T> {\n    // Resolve field value\n    const fieldValue = this.discovery.resolveProperty(\n      constraint.field,\n      criteria as any,\n    );\n\n    // Resolve constraint value (handle self-references)\n    const constraintValue = this.resolveConstraintValue(\n      constraint.value,\n      criteria,\n    );\n\n    // Get operator strategy from registry\n    const operatorStrategy = operatorRegistry.get(constraint.operator);\n    if (!operatorStrategy) {\n      return {\n        value: false as T,\n        isPassed: false,\n        message: `Invalid operator: ${constraint.operator}. Please provide a valid operator. The operator is case-sensitive.`,\n      };\n    }\n\n    // Create operator context\n    const context: OperatorContext = {\n      fieldValue,\n      constraintValue,\n      criteria,\n      fieldPath: constraint.field,\n    };\n\n    // Validate inputs\n    const validation = operatorStrategy.validate(context);\n    if (!validation.isValid) {\n      return {\n        value: false as T,\n        isPassed: false,\n        message:\n          validation.error ||\n          `Validation failed for operator: ${constraint.operator}`,\n      };\n    }\n\n    // Evaluate operator\n    const isPassed = operatorStrategy.evaluate(context);\n    const value = isPassed as T;\n\n    // Format message if provided\n    let formattedMessage: string | undefined;\n    if (constraint.message) {\n      formattedMessage = operatorStrategy.formatMessage\n        ? operatorStrategy.formatMessage(constraint.message, context)\n        : constraint.message;\n\n      formattedMessage = this.mutateResultMessage(\n        {\n          value,\n          isPassed,\n          message: formattedMessage,\n        },\n        {\n          ...criteria,\n          self: {\n            value: constraint.value,\n            input: fieldValue,\n          },\n        },\n        isPassed,\n      ).message;\n    }\n\n    return {\n      value,\n      isPassed,\n      message: formattedMessage,\n    };\n  }\n\n  /**\n   * Resolves constraint value, handling self-references\n   */\n  private resolveConstraintValue(value: any, criteria: Criteria): any {\n    if (Array.isArray(value)) {\n      return value.map((x) =>\n        typeof x === \"string\" && x.includes(\"$.\")\n          ? this.discovery.resolveProperty(x, criteria as any)\n          : x,\n      );\n    }\n\n    if (typeof value === \"string\" && value.includes(\"$.\")) {\n      return this.discovery.resolveProperty(value, criteria as any);\n    }\n\n    return value;\n  }\n\n  /**\n   * Mutates the result message by resolving any text path expressions.\n   * If the result is falsy, the default value is returned.\n   * If the result does not have a message property, the result is returned as is.\n   * The criteria object is used to resolve the text path expressions.\n   * The result is mutated in place.\n   *\n   * @param payload The result to mutate.\n   * @param criteria The criteria object to resolve the text path expressions.\n   * @param defaultValue The default value to return if the result is falsy.\n   * @returns The mutated result.\n   * @example\n   * ```typescript\n   * const result = {\n   *  result: false,\n   *  message: \"Password is valid and contains username($.username), name($.name) and family($.family)\",\n   * };\n   * const criteria = {\n   *  username: \"johndoe\",\n   *  name: \"john\",\n   *  family: \"doe\",\n   * };\n   * const resolvedResult = evaluator.mutateResultMessage(result, criteria);\n   * console.log(resolvedResult); // { result: false, message: \"Password is valid and contains username(john-doe), name(john) and family(doe)\" }\n   * ```\n   */\n  mutateResultMessage(\n    payload: EvaluationResult<T>,\n    criteria: Criteria,\n    defaultValue: boolean,\n  ): EvaluationResult<T> {\n    if (\n      payload?.message &&\n      isStringOperator(payload.message) &&\n      payload.message.includes(\"$.\")\n    ) {\n      return {\n        isPassed: payload.isPassed,\n        value: (payload.value ?? defaultValue) as T,\n        message: this.discovery.resolveTextPathExpressions(\n          payload.message!,\n          criteria as any,\n        ),\n      };\n    }\n\n    return Object.assign(\n      {},\n      {\n        isPassed: payload.isPassed,\n        value: (payload.value ?? defaultValue) as T,\n        message: payload.message,\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "packages/core/src/services/index.ts",
    "content": "export * from \"./builder\";\nexport * from \"./evaluator\";\nexport * from \"./introspector\";\nexport * from \"./logger\";\nexport * from \"./mutator\";\nexport * from \"./object-discovery\";\nexport * from \"./rule-engine\";\n"
  },
  {
    "path": "packages/core/src/services/introspector.ts",
    "content": "import { RuleTypeError, clone } from \"@root/utils\";\nimport { Logger } from \"@root/services/logger\";\nimport { ObjectDiscovery } from \"@root/services/object-discovery\";\nimport { operatorRegistry } from \"@root/operators/registry\";\n// Enums\nimport { Operators, ConditionTypes } from \"@root/enums\";\n// Types\nimport type {\n  RuleType,\n  OperatorsType,\n  IntrospectionStep,\n  IntrospectionResult,\n  EngineResult,\n  CriteriaRange,\n  Constraint,\n  ConditionType,\n  Condition,\n} from \"@root/types\";\n\n/**\n * Enhanced introspection result with operator metadata\n */\nexport interface EnhancedIntrospectionResult<R = any>\n  extends IntrospectionResult<R> {\n  /**\n   * Metadata about operators used in the rule\n   */\n  operatorMetadata?: {\n    /**\n     * All operators used in the rule\n     */\n    usedOperators: Set<OperatorsType>;\n\n    /**\n     * Operators grouped by category\n     */\n    operatorsByCategory: Record<string, OperatorsType[]>;\n\n    /**\n     * Field types expected by the rule\n     */\n    expectedFieldTypes: Record<string, Set<string>>;\n\n    /**\n     * Validation warnings\n     */\n    warnings?: string[];\n  };\n\n  /**\n   * Rule complexity metrics\n   */\n  complexity?: {\n    /**\n     * Maximum nesting depth\n     */\n    maxDepth: number;\n\n    /**\n     * Total number of conditions\n     */\n    totalConditions: number;\n\n    /**\n     * Total number of constraints\n     */\n    totalConstraints: number;\n\n    /**\n     * Number of unique fields referenced\n     */\n    uniqueFields: number;\n  };\n}\n\nexport class Introspector {\n  private steps: IntrospectionStep[] | undefined;\n  private readonly discovery = new ObjectDiscovery();\n  private usedOperators: Set<OperatorsType> = new Set();\n  private fieldTypes: Map<string, Set<string>> = new Map();\n  private warnings: string[] = [];\n  private maxDepth = 0;\n  private totalConditions = 0;\n  private totalConstraints = 0;\n  private uniqueFields: Set<string> = new Set();\n\n  /**\n   * Given a rule, checks the constraints and conditions to determine\n   * the possible range of input criteria which would be satisfied by the rule.\n   * Enhanced with operator metadata and validation.\n   *\n   * @template R The type of the rule result.\n   * @param rule The rule to evaluate.\n   * @param options Introspection options\n   * @param options.includeMetadata Whether to include operator metadata in the result.\n   * @param options.includeComplexity Whether to include complexity metrics in the result.\n   * @param options.validateOperators Whether to validate operators in the rule.\n   * @throws RuleTypeError if the rule is not granular\n   */\n  introspect<R = any>(\n    rule: RuleType<R>,\n    options?: {\n      includeMetadata?: boolean;\n      includeComplexity?: boolean;\n      validateOperators?: boolean;\n    },\n  ): EnhancedIntrospectionResult<R> {\n    // Reset state\n    this.resetState();\n\n    // The ruleset needs to be granular for this operation to work\n    if (!this.discovery.isGranular(rule)) {\n      throw new RuleTypeError(\n        \"The provided rule is not granular. A granular rule is required for Introspection\",\n      );\n    }\n\n    // Initialize a clean steps array each time we introspect\n    this.steps = [];\n\n    const conditions = this.discovery.getConditions(rule);\n\n    // Then we map each result to the condition that produces\n    // it to create a map of results to conditions\n    const conditionMap = new Map<EngineResult<R>, Array<Condition<R>>>();\n    for (const condition of conditions) {\n      const result = condition.result!;\n      const data = conditionMap.get(result) ?? [];\n      if (!data.length) {\n        conditionMap.set(result, data);\n      }\n\n      data.push(condition);\n    }\n\n    // Using this information, we can build the skeleton of the introspected criteria range\n    const criteriaRange: Array<CriteriaRange<R>> = [];\n    // Initialize criteria range with all possible results\n    // This will be used to populate the criteria ranges for each result\n    const conditionsKeys = conditionMap.keys();\n    // @ts-ignore\n    for (const result of conditionsKeys) {\n      criteriaRange.push({\n        result,\n        options: [],\n      });\n    }\n\n    // Populate criteria ranges\n    const results = this.resolveCriteriaRanges(criteriaRange, conditionMap);\n\n    // Build the base introspection result\n    const baseResult: IntrospectionResult<R> = {\n      results,\n      ...(\"default\" in rule && rule.default !== undefined\n        ? { default: rule.default }\n        : {}),\n    };\n\n    // Add enhanced metadata if requested\n    if (options?.includeMetadata || options?.includeComplexity) {\n      const enhancedResult: EnhancedIntrospectionResult<R> = {\n        ...baseResult,\n      };\n\n      if (options.includeMetadata) {\n        enhancedResult.operatorMetadata = this.buildOperatorMetadata();\n      }\n\n      if (options.includeComplexity) {\n        enhancedResult.complexity = {\n          maxDepth: this.maxDepth,\n          totalConditions: this.totalConditions,\n          totalConstraints: this.totalConstraints,\n          uniqueFields: this.uniqueFields.size,\n        };\n      }\n\n      return enhancedResult;\n    }\n\n    return baseResult;\n  }\n\n  /**\n   * Validate that all operators in the rule are registered\n   */\n  validateOperators(rule: RuleType): { isValid: boolean; errors: string[] } {\n    const errors: string[] = [];\n    const conditions = this.discovery.getConditions(rule);\n\n    this.validateConditionsOperators(conditions, errors);\n\n    return {\n      isValid: errors.length === 0,\n      errors,\n    };\n  }\n\n  /**\n   * Get all operators used in a rule\n   */\n  getUsedOperators(rule: RuleType): Set<OperatorsType> {\n    const operators = new Set<OperatorsType>();\n    const conditions = this.discovery.getConditions(rule);\n\n    this.collectOperatorsFromConditions(conditions, operators);\n\n    return operators;\n  }\n\n  /**\n   * Validate operators in conditions recursively\n   */\n  private validateConditionsOperators(\n    conditions: Condition[],\n    errors: string[],\n  ): void {\n    for (const condition of conditions) {\n      const type = this.discovery.conditionType(condition);\n      if (!type) continue;\n\n      for (const node of condition[type]!) {\n        if (this.discovery.isConstraint(node)) {\n          const constraint = node as Constraint;\n\n          if (!operatorRegistry.has(constraint.operator)) {\n            errors.push(\n              `Unknown operator \"${constraint.operator}\" for field \"${constraint.field}\"`,\n            );\n          }\n        } else if (this.discovery.isCondition(node)) {\n          this.validateConditionsOperators([node as Condition], errors);\n        }\n      }\n    }\n  }\n\n  /**\n   * Collect operators from conditions recursively\n   */\n  private collectOperatorsFromConditions(\n    conditions: Condition[],\n    operators: Set<OperatorsType>,\n  ): void {\n    for (const condition of conditions) {\n      const type = this.discovery.conditionType(condition);\n      if (!type) continue;\n\n      for (const node of condition[type]!) {\n        if (this.discovery.isConstraint(node)) {\n          const constraint = node as Constraint;\n          operators.add(constraint.operator);\n        } else if (this.discovery.isCondition(node)) {\n          this.collectOperatorsFromConditions([node as Condition], operators);\n        }\n      }\n    }\n  }\n\n  /**\n   * Build operator metadata from collected information\n   */\n  private buildOperatorMetadata() {\n    const operatorsByCategory: Record<string, OperatorsType[]> = {};\n\n    // Group operators by category\n    for (const operatorName of this.usedOperators) {\n      const operator = operatorRegistry.get(operatorName);\n      if (operator) {\n        const category = operator.metadata.category;\n        if (!operatorsByCategory[category]) {\n          operatorsByCategory[category] = [];\n        }\n        operatorsByCategory[category].push(operatorName);\n      }\n    }\n\n    // Convert field types map to record\n    const expectedFieldTypes: Record<string, Set<string>> = {};\n    for (const [field, types] of this.fieldTypes) {\n      expectedFieldTypes[field] = types;\n    }\n\n    return {\n      usedOperators: this.usedOperators,\n      operatorsByCategory,\n      expectedFieldTypes,\n      warnings: this.warnings.length > 0 ? this.warnings : undefined,\n    };\n  }\n\n  /**\n   * Reset internal state\n   */\n  private resetState(): void {\n    this.steps = undefined;\n    this.usedOperators.clear();\n    this.fieldTypes.clear();\n    this.warnings = [];\n    this.maxDepth = 0;\n    this.totalConditions = 0;\n    this.totalConstraints = 0;\n    this.uniqueFields.clear();\n  }\n\n  /**\n   * Populates the criteria range options with the possible range of input values\n   * @param criteriaRanges The criteria range to populate.\n   * @param conditionMap The map of results to conditions.\n   * @param parentType The type of the parent condition.\n   * @param depth The current recursion depth.\n   */\n  private resolveCriteriaRanges<T>(\n    criteriaRanges: Array<CriteriaRange<T>>,\n    conditionMap: Map<EngineResult<T>, Array<Condition<T>>>,\n    parentType?: ConditionType,\n    depth = 0,\n  ): CriteriaRange<T>[] {\n    // Track max depth\n    this.maxDepth = Math.max(this.maxDepth, depth);\n\n    // For each set of conditions which produce the same result\n    for (const [result, conditions] of conditionMap) {\n      this.totalConditions += conditions.length;\n\n      // For each condition in that set\n      for (const condition of conditions) {\n        const type = this.discovery.conditionType(condition);\n        if (!type) {\n          continue;\n        }\n\n        try {\n          Logger.debug(\n            `\\nIntrospector: Introspecting result \"${JSON.stringify(result)}\"`,\n          );\n        } catch {\n          Logger.debug(`\\nIntrospector: Introspecting result \"${result}\"`);\n        }\n\n        // Find the criteria range object for the result\n        let criteriaRangeItem = criteriaRanges.find(\n          (criteria) => criteria.result == result,\n        )!;\n        criteriaRangeItem = this.populateCriteriaRangeOptions<T>(\n          criteriaRangeItem,\n          condition,\n          depth,\n          parentType,\n        );\n\n        // Iterate over each property of the condition\n        for (const node of condition[type]!) {\n          if (this.discovery.isCondition(node)) {\n            const condition = node as Condition<T>;\n            criteriaRangeItem = this.resolveCriteriaRanges<T>(\n              [criteriaRangeItem],\n              new Map<EngineResult<T>, Condition<T>[]>([[result, [condition]]]),\n              type,\n              depth + 1,\n            ).pop()!;\n          }\n\n          // Update the original set of criteria range objects\n          // with the updated criteria range object\n          const index = criteriaRanges.findIndex(\n            (criteria) => criteria.result == result,\n          );\n          criteriaRanges[index] = criteriaRangeItem;\n        }\n      }\n    }\n\n    return criteriaRanges;\n  }\n\n  /**\n   * Updates a criteria range entry based on the constraint and condition type.\n   * Enhanced with operator validation and metadata collection.\n   */\n  private populateCriteriaRangeOptions<T>(\n    criteriaRange: CriteriaRange<T>,\n    condition: Condition,\n    depth: number,\n    parentType?: ConditionType,\n  ): CriteriaRange<T> {\n    const type = this.discovery.conditionType(condition) as ConditionType;\n    const options = new Map<string, Record<string, unknown>>();\n\n    for (const node of condition[type]!) {\n      if (!this.discovery.isConstraint(node)) {\n        continue;\n      }\n\n      const constraint = node as Constraint;\n      this.totalConstraints++;\n      this.uniqueFields.add(constraint.field);\n\n      // Collect operator metadata\n      this.usedOperators.add(constraint.operator);\n\n      // Validate operator and collect field types\n      const operator = operatorRegistry.get(constraint.operator);\n      if (operator) {\n        // Track expected field types\n        if (!this.fieldTypes.has(constraint.field)) {\n          this.fieldTypes.set(constraint.field, new Set());\n        }\n        const fieldTypeSet = this.fieldTypes.get(constraint.field)!;\n        operator.metadata.acceptedFieldTypes.forEach((type) =>\n          fieldTypeSet.add(type),\n        );\n      } else {\n        this.warnings.push(\n          `Unknown operator \"${constraint.operator}\" for field \"${constraint.field}\"`,\n        );\n      }\n\n      Logger.debug(\n        `Introspector: Processing \"${constraint.field} (${constraint.operator})\" in \"${type}\" condition`,\n      );\n\n      // Check if we already have an entry with the same field\n      // and if so, update it instead of creating a new one\n      let option = options.get(constraint.field) ?? {};\n      option = this.updateCriteriaRangeOptions(option, constraint, type);\n      options.set(constraint.field, option);\n    }\n\n    if ([ConditionTypes.OR, ConditionTypes.NONE].includes(type)) {\n      Array.from(options.values()).forEach((option) => {\n        criteriaRange = this.addOptionToCriteriaRange<T>(\n          type,\n          parentType!,\n          criteriaRange,\n          option,\n          depth,\n        );\n\n        // Debug the last introspection\n        Logger.debug(\"Introspector: Step complete\", this.lastStep);\n      });\n    }\n\n    if (type === ConditionTypes.AND) {\n      criteriaRange = this.addOptionToCriteriaRange<T>(\n        type,\n        parentType!,\n        criteriaRange,\n        Array.from(options.values()).reduce((prev, curr) => {\n          for (const [key, value] of Object.entries(curr)) {\n            prev[key] = Object.prototype.hasOwnProperty.call(prev, key)\n              ? [...new Set([prev[key], value].flat())]\n              : value;\n          }\n\n          return prev;\n        }, {}),\n        depth,\n      );\n\n      // Debug the last introspection\n      Logger.debug(\"Introspector: Step complete\", this.lastStep);\n    }\n\n    return criteriaRange;\n  }\n\n  /**\n   * Updates a criteria range option based on the constraint and condition type.\n   * @param option The option to update.\n   * @param constraint The constraint to update the option with.\n   * @param type The current condition type.\n   */\n  private updateCriteriaRangeOptions(\n    option: Record<string, unknown>,\n    constraint: Constraint,\n    type: ConditionType,\n  ): Record<string, unknown> {\n    // We need to clone the constraint because we will be modifying it\n    const $constraint = clone(constraint);\n\n    // We can consider a 'None' as a not 'All' and flip all the operators\n    // To be done on any 'None' type condition or on any child\n    // of a 'None' type condition.\n    if (\n      type === ConditionTypes.NONE ||\n      this.isCurrentStepChildOf(ConditionTypes.NONE)\n    ) {\n      const negatedOperator = operatorRegistry.getNegatedOperator(\n        $constraint.operator,\n      );\n      if (negatedOperator) {\n        $constraint.operator = negatedOperator;\n      } else {\n        this.warnings.push(\n          `No negated operator found for \"${$constraint.operator}\"`,\n        );\n      }\n    }\n\n    if (!Object.prototype.hasOwnProperty.call(option, $constraint.field)) {\n      // When condition is an all, we need to create a new object in the criteria range\n      // options and add all the possible inputs which would satisfy the condition.\n      if (type === ConditionTypes.AND || type === ConditionTypes.NONE) {\n        switch ($constraint.operator) {\n          case Operators.Equals:\n          case Operators.In:\n            option[$constraint.field] = $constraint.value;\n            break;\n          default:\n            option[$constraint.field] = {\n              operator: $constraint.operator,\n              value: $constraint.value,\n            };\n            break;\n        }\n\n        return option;\n      }\n\n      // When condition is an any, we need to create a new object in the criteria range\n      // options for each criterion in the condition and add all the possible inputs\n      // which would satisfy the criterion.\n      if (type === ConditionTypes.OR) {\n        switch ($constraint.operator) {\n          case Operators.Equals:\n          case Operators.In:\n            return { [$constraint.field]: $constraint.value };\n          default:\n            return {\n              [$constraint.field]: {\n                operator: $constraint.operator,\n                value: $constraint.value,\n              },\n            };\n        }\n      }\n    }\n\n    let value = $constraint.value;\n    if ($constraint.operator !== Operators.Equals) {\n      value = { operator: $constraint.operator, value: $constraint.value };\n    }\n\n    option[$constraint.field] = [\n      ...new Set([option[$constraint.field], value].flat()),\n    ];\n\n    return option;\n  }\n\n  /**\n   * Adds an option to a criteria range entry based on the condition type and parent type.\n   * @param currType The current condition type.\n   * @param parentType The type of the parent condition.\n   * @param entry The criteria range entry to update.\n   * @param option The option to update the criteria range entry with.\n   * @param depth The current recursion depth.\n   */\n  private addOptionToCriteriaRange<T>(\n    currType: ConditionType,\n    parentType: ConditionType,\n    entry: CriteriaRange<T>,\n    option: Record<string, unknown>,\n    depth: number,\n  ): CriteriaRange<T> {\n    const lastIdx = entry.options?.length! - 1;\n\n    // We create new objects in the option array\n    if (\n      [ConditionTypes.AND, ConditionTypes.NONE].includes(currType) &&\n      parentType === ConditionTypes.OR\n    ) {\n      // If we encounter this pair in a deeply nested condition, we need to clone\n      // the last option and add the options from the all by either appending\n      // them if the key is new, or replacing the 'any' with the new values.\n      if (depth > 1) {\n        // We should start based on the last option added\n        const baseOption = clone(entry.options?.[entry.options.length - 1])!;\n\n        // If the previous step added anything to the base option, then we must first\n        // remove these changes. For condition types of 'Any' or 'None' a step\n        // is created for each property in the condition. Therefore, we must\n        // remove the changes from step(s) which are at the same depth of\n        // the last step.\n        if (this.lastStep?.changes && this.lastStep.changes.length) {\n          const depth = this.lastStep.depth;\n\n          const steps = [...(this.steps ?? [])];\n          let step = steps.pop();\n\n          while (step?.depth === depth) {\n            for (const change of step.changes!) {\n              if (baseOption[change.key] === change.value) {\n                delete baseOption[change.key];\n              }\n\n              if (Array.isArray(baseOption[change.key])) {\n                baseOption[change.key] = (baseOption[change.key] as []).filter(\n                  (o) =>\n                    Array.isArray(change.value)\n                      ? !change.value.includes(o)\n                      : o != change.value,\n                );\n              }\n            }\n            step = steps.pop();\n          }\n        }\n\n        for (const [key, value] of Object.entries(option)) {\n          baseOption[key] = Object.prototype.hasOwnProperty.call(\n            baseOption,\n            key,\n          )\n            ? [...new Set([baseOption[key], value].flat())]\n            : value;\n        }\n\n        this.steps?.push({\n          parentType,\n          currType,\n          depth,\n          option: baseOption,\n        });\n\n        Logger.debug(\n          `Introspector: + new option to criteria range based on last root parent\"`,\n        );\n\n        entry.options?.push(baseOption);\n        return entry;\n      }\n\n      this.steps?.push({ parentType, currType, depth, option });\n      Logger.debug(`Introspector: + new option to criteria range`);\n\n      entry.options?.push(option);\n\n      return entry;\n    }\n\n    // We add these options onto the last object in the option array\n    if (\n      (ConditionTypes.OR === currType && ConditionTypes.OR === parentType) ||\n      (ConditionTypes.OR === currType &&\n        [ConditionTypes.AND, ConditionTypes.NONE].includes(parentType)) ||\n      ([ConditionTypes.AND, ConditionTypes.NONE].includes(currType) &&\n        [ConditionTypes.AND, ConditionTypes.NONE].includes(parentType))\n    ) {\n      const changes: IntrospectionStep[\"changes\"] = [];\n      for (const [key, value] of Object.entries(option)) {\n        if (entry.options) {\n          if (!entry.options[lastIdx]) {\n            entry.options[lastIdx] = {};\n          }\n          // If the last option already has this key, we need to update it\n          // eslint-disable-next-line no-prototype-builtins\n          entry.options[lastIdx][key] = entry.options?.[lastIdx].hasOwnProperty(\n            key,\n          )\n            ? [...new Set([entry.options[lastIdx][key], value].flat())]\n            : value;\n        }\n\n        changes.push({ key, value });\n      }\n\n      this.steps?.push({\n        parentType,\n        currType,\n        depth,\n        option: entry.options?.[lastIdx]!,\n        changes,\n      });\n\n      Logger.debug(`Introspector: Updating previous option with new values\"`);\n\n      return entry;\n    }\n\n    this.steps?.push({ parentType, currType, depth, option });\n    Logger.debug(`Introspector: + new option to criteria range\"`);\n\n    entry.options?.push(option);\n    return entry;\n  }\n\n  /**\n   * Checks if the current condition being introspected is the child\n   * of some parent condition with a given type.\n   * @param parentType The type of the parent condition.\n   */\n  private isCurrentStepChildOf(parentType: ConditionType): boolean {\n    if (!this.steps?.length) {\n      return false;\n    }\n\n    // Clone the step array so that we can pop items off it\n    const steps = [...this.steps];\n    let step = steps.pop();\n\n    // Check ancestors until we reach the first root condition\n    while (step?.depth! >= 0) {\n      if (step!.currType === parentType || step!.parentType === parentType)\n        return true;\n\n      step = steps.pop();\n    }\n\n    return false;\n  }\n\n  /** Returns the last step in the introspection process. */\n  get lastStep(): IntrospectionStep | null {\n    // @ts-ignore\n    return this.steps?.length ? this.steps[this.steps.length - 1] : null;\n  }\n}\n"
  },
  {
    "path": "packages/core/src/services/logger.ts",
    "content": "export class Logger {\n  static debug(...opts: any[]): void {\n    if (!process.env.DEBUG) return;\n    console.debug(...opts);\n  }\n}\n"
  },
  {
    "path": "packages/core/src/services/mutator.ts",
    "content": "// Utilities\nimport { clone } from \"@root/utils\";\nimport { createHash } from \"node:crypto\";\nimport { EventEmitter } from \"eventemitter3\";\nimport { Logger } from \"@root/services/logger\";\nimport { ObjectDiscovery } from \"@root/services/object-discovery\";\n// Types\nimport type { CriteriaObject, Criteria } from \"@root/types\";\n\n/**\n * The Mutator class allows for the modification of criteria objects before they are evaluated against a rule.\n * Mutations are added to the mutator instance and are executed when the criteria object contains the mutation key.\n * Mutations are cached to prevent duplicate executions of the same mutation on the same object.\n *\n * @example\n * const mutator = new Mutator();\n * mutator.add(\"uppercase\", (value) => value.toUpperCase());\n * mutator.add(\"lowercase\", (value) => value.toLowerCase());\n * mutator.add(\"reverse\", (value) => value.split(\"\").reverse().join(\"\"));\n * mutator.add(\"trim\", (value) => value.trim());\n * mutator.add(\"replace\", (value, criteria) => {\n *  const { find, replace } = criteria;\n *  return value.replace(find, replace);\n * });\n * mutator.mutate({ name: \"John Doe\" }); // { name: \"John Doe\" }\n * mutator.mutate({ name: \"John Doe\", find: \"John\", replace: \"Jane\" }); // { name: \"Jane Doe\", find: \"John\", replace: \"Jane\" }\n * mutator.applyMutations({ name: \"John Doe\", find: \"John\", replace: \"Jane\" }); // { name: \"Jane Doe\", find: \"John\", replace: \"Jane\" }\n */\nexport class Mutator {\n  private readonly cache = new Map<string, any>();\n  private readonly buffer = new Map<string, boolean>();\n  private readonly mutations = new Map<string, Function>();\n  private readonly eventEmitter = new EventEmitter();\n  private readonly discovery = new ObjectDiscovery();\n\n  /**\n   * Adds a mutation or mutations to the mutator instance.\n   * The mutation(s) will be executed when the criteria object contains the mutation key.\n   *\n   * @param options The mutation name and function to execute.\n   * @example\n   * mutator.add(\"uppercase\", (value) => value.toUpperCase());\n   * mutator.add(\"lowercase\", (value) => value.toLowerCase());\n   * mutator.add(\"reverse\", (value) => value.split(\"\").reverse().join(\"\"));\n   * mutator.add(\"trim\", (value) => value.trim());\n   * mutator.add(\"replace\", (value, criteria) => { const { find, replace } = criteria; return value.replace(find, replace); });\n   * mutator.add([{ name: \"uppercase\", mutation: (value) => value.toUpperCase() }, { name: \"lowercase\", mutation: (value) => value.toLowerCase() }]);\n   */\n  add(options: Array<{ name: string; mutation: Function }>): void;\n  add(options: string, mutation: Function): void;\n  add(\n    options: string | Array<{ name: string; mutation: Function }>,\n    mutation?: Function,\n  ): void {\n    if (Array.isArray(options)) {\n      for (const { name, mutation } of options) {\n        this.mutations.set(name, mutation);\n      }\n      return;\n    }\n\n    this.mutations.set(options, mutation!);\n  }\n\n  /**\n   * Removes a mutation or mutations from the mutator instance.\n   * Any cached mutation values for this mutation will be purged.\n   *\n   * @param {string | Array<string>} names The name of the mutation.\n   * @example\n   * mutator.remove(\"uppercase\");\n   * mutator.remove([\"reverse\", \"trim\"]);\n   */\n  remove(names: Array<string>): void;\n  remove(names: string): void;\n  remove(names: string | Array<string>): void {\n    if (Array.isArray(names)) {\n      for (const name of names) {\n        this.clearCache(name);\n        this.mutations.delete(name);\n      }\n      return;\n    }\n\n    this.clearCache(names);\n    this.mutations.delete(names);\n  }\n\n  /**\n   * Removes all mutations from the mutator instance.\n   * Clears all cached mutation values.\n   */\n  removeAll(): void {\n    this.mutations.clear();\n    this.cache.clear();\n  }\n\n  /**\n   * Clears the mutator cache.\n   * The entire cache, or cache for a specific mutator can be cleared\n   * by passing or omitting the mutator name as an argument.\n   *\n   * @param name The mutator name to clear the cache for.\n   */\n  clearCache(name?: string): void {\n    if (!name) {\n      this.cache.clear();\n      return;\n    }\n\n    for (const key of this.cache.keys()) {\n      if (key.startsWith(name)) {\n        this.cache.delete(key);\n      }\n    }\n  }\n\n  /**\n   * Mutates and returns a criteria object.\n   * If the criteria is an array, each item in the array will be mutated.\n   * If the criteria do not contain any mutations, it will be returned as is.\n   * If the criteria is mutable, it will be cloned, mutated and returned.\n   *\n   * @param criteria The criteria to mutate.\n   * @returns The mutated criteria object.\n   */\n  async mutate(criteria: Criteria): Promise<Criteria> {\n    // Handles checking the mutability of a criteria object\n    // If it is mutable it will be cloned, mutated and returned\n    const exec = async (criteria: CriteriaObject) => {\n      // If there are no mutations or the criteria does not contain\n      // any of the mutation keys, return the criteria as is.\n      if (!this.mutations.size || !this.hasMutations(criteria)) {\n        return criteria;\n      }\n\n      // Make a copy of the criteria.\n      const copy = clone(criteria);\n\n      // Apply the mutations to the copy and return it.\n      await this.applyMutations(copy);\n\n      return copy;\n    };\n\n    // If the criteria is an array, we want to apply the mutations\n    // to each item in the array in parallel.\n    if (Array.isArray(criteria)) {\n      return Promise.all(\n        criteria.map(\n          (criteriaObj) =>\n            new Promise(async (resolve) => {\n              const mutated = await exec(criteriaObj);\n\n              resolve(mutated);\n            }),\n        ),\n      );\n    } else {\n      return exec(criteria);\n    }\n  }\n\n  /**\n   * Checks if the criteria contains any mutate-able properties.\n   * Recurses through nested objects.\n   * Returns true if a mutate-able property is found.\n   *\n   * @param criteria The criteria to check.\n   * @param result Whether a mutate-able property has been found.\n   */\n  private hasMutations(criteria: CriteriaObject, result = false): boolean {\n    // If we have already found a mutation, we can stop.\n    if (result) return true;\n\n    for (const key of Object.keys(criteria)) {\n      if (result) return true;\n\n      // Prepare a dotted path to the current property.\n      const path = this.discovery.resolveProperty(key, criteria);\n\n      // If the value is an object, we should recurse.\n      result = result || path !== undefined;\n    }\n\n    return result;\n  }\n\n  /**\n   * Recursively applies mutations to the criteria.\n   * Mutations are executed in parallel.\n   *\n   * @param criteria The criteria to mutate.\n   */\n  private async applyMutations(criteria: CriteriaObject): Promise<void> {\n    const promises = [...this.mutations.keys()].map(\n      async (key) =>\n        new Promise(async (resolve) => {\n          // Prepare a dotted path to the current property.\n          const value = this.discovery.resolveProperty(key, criteria);\n          if (typeof value !== \"undefined\") {\n            const processResult = await this.execMutation(key, criteria);\n            criteria = this.discovery.updateProperty(\n              key,\n              criteria,\n              processResult,\n            );\n          }\n\n          resolve(value);\n        }),\n    );\n\n    await Promise.all(promises);\n  }\n\n  /**\n   * Executes a mutation.\n   * Defers duplicate executions to the same object from a memory cache.\n   * Mutations are executed in parallel.\n   *\n   * @param mutationKey The criteria property to execute the mutation on.\n   * @param criteria The criteria to execute the mutation with.\n   */\n  private async execMutation(\n    mutationKey: string,\n    criteria: CriteriaObject,\n  ): Promise<any> {\n    // Resolve the value of the property to mutate.\n    const value = this.discovery.resolveProperty(mutationKey, criteria);\n\n    // Create a cache key\n    const cacheKey = `${mutationKey}${createHash(\"sha256\").update(value.toString()).digest(\"hex\")}`;\n\n    // If the mutation has already been executed, return the cached result.\n    if (this.cache.has(cacheKey)) {\n      Logger.debug(`Cache hit on \"${mutationKey}\" with param \"${value}\"`);\n      return this.cache.get(cacheKey);\n    }\n\n    // If the mutation is already in progress, wait for it to finish.\n    if (this.buffer.get(cacheKey)) {\n      return await new Promise((resolve) => {\n        Logger.debug(\n          `Waiting on mutation \"${mutationKey}\" with param \"${value}\"`,\n        );\n        this.eventEmitter.once(`mutation:${cacheKey}`, (result) => {\n          Logger.debug(\n            `Resolved mutation \"${mutationKey}\" with param \"${value}\"`,\n          );\n          resolve(result);\n        });\n      });\n    }\n\n    // Set the buffer to true to indicate that the mutation is in progress.\n    // This prevents duplicate executions of the same mutation.\n    this.buffer.set(cacheKey, true);\n\n    // Execute the mutation\n    Logger.debug(`Running mutation \"${mutationKey}\" with param \"${value}\"`);\n    const mutation = this.mutations.get(mutationKey) ?? (() => value);\n    const result = await mutation(value, criteria);\n\n    // Cache the result and release the buffer to false.\n    this.cache.set(cacheKey, result);\n    this.buffer.set(cacheKey, false);\n\n    // Emit an event to indicate that the mutation has been executed.\n    this.eventEmitter.emit(`mutation:${cacheKey}`, result);\n\n    return result;\n  }\n}\n"
  },
  {
    "path": "packages/core/src/services/object-discovery.ts",
    "content": "// Utilities\nimport { isEmpty } from \"ramda\";\nimport { JSONPath } from \"jsonpath-plus\";\nimport { isObject, extractJsonPathExpressions } from \"@root/utils\";\n// Enums\nimport { ConditionTypes } from \"@root/enums\";\n// Types\nimport type {\n  RuleType,\n  CriteriaObject,\n  Criteria,\n  Constraint,\n  ConditionType,\n  Condition,\n} from \"@root/types\";\n\n/**\n * Object discovery service. Used to discover information about objects.\n */\nexport class ObjectDiscovery<T = any> {\n  /**\n   * Returns the conditions of a rule.\n   * @param rule The rule to get the conditions from.\n   */\n  getConditions(rule: RuleType<T>): Array<Condition<T>> {\n    return Array.isArray(rule.conditions) ? rule.conditions : [rule.conditions];\n  }\n\n  /**\n   * Returns the type of condition passed to the function.\n   * @param condition The condition to check.\n   */\n  conditionType(condition: Condition<T>): ConditionType | null {\n    if (ConditionTypes.OR in condition) {\n      return ConditionTypes.OR;\n    }\n    if (ConditionTypes.AND in condition) {\n      return ConditionTypes.AND;\n    }\n    if (ConditionTypes.NONE in condition) {\n      return ConditionTypes.NONE;\n    }\n\n    return null;\n  }\n\n  /**\n   * Checks the rule to see if it is granular.\n   * @param rule The rule to check.\n   */\n  isGranular(rule: RuleType<T>): boolean {\n    const conditions = this.getConditions(rule);\n\n    // Checks each condition making sure it has a result property.\n    for (const condition of conditions) {\n      if (\n        !this.isCondition(condition) ||\n        !(\"result\" in condition) ||\n        condition.result === undefined\n      ) {\n        return false;\n      }\n    }\n\n    return true;\n  }\n\n  /**\n   * Checks an object to see if it is a valid condition.\n   * @param obj The object to check.\n   */\n  isCondition(obj: object): obj is Condition {\n    return isObject(obj) && !!this.conditionType(obj);\n  }\n\n  /**\n   * Checks an object to see if it is a valid constraint.\n   * @param obj The object to check.\n   */\n  isConstraint(obj: object): obj is Constraint {\n    return isObject(obj) && \"field\" in obj && \"operator\" in obj;\n  }\n\n  /**\n   * Resolves a nested property from a string as an object path for a single object.\n   * @param path The path to resolve.\n   * @param json The object to resolve the path against.\n   */\n  resolveProperty(path: string, json: CriteriaObject<T>): any;\n\n  /**\n   * Resolves a nested property from a string as an object path for an array.\n   * @param path The path to resolve.\n   * @param json The array to resolve the path against.\n   */\n  resolveProperty(path: string, json: Array<T>): any;\n\n  /**\n   * Resolves a nested property from a sting as an object path.\n   * @param path The path to resolve.\n   * @param json The object to resolve the path against.\n   */\n  resolveProperty(path: string, json: Criteria<T>): any {\n    if (!path?.includes(\"$.\") && isObject(json)) {\n      return (json as CriteriaObject)[path];\n    }\n    const result = JSONPath({ path, json: json as any });\n    if (Array.isArray(result) && result.length === 1) {\n      return result[0];\n    }\n\n    return isEmpty(result) ? undefined : result;\n  }\n\n  /**\n   * Updates a property in a JSON object. Supports nested properties.\n   * @param path The path to the property to update.\n   * @param json The JSON object to update.\n   * @param value The value to set the property to.\n   */\n  updateProperty(path: string, json: CriteriaObject<T>, value: any): any;\n\n  /**\n   * Updates a property in a JSON array. Supports nested properties.\n   * @param path The path to the property to update.\n   * @param json The JSON array to update.\n   * @param value The value to set the property to.\n   */\n  updateProperty(path: string, json: Array<T>, value: any): any;\n\n  /**\n   * Updates a property in a JSON object. Supports nested properties.\n   *\n   * @param path The path to the property to update.\n   * @param json The JSON object to update.\n   * @param value The value to set the property to.\n   * @returns The updated JSON object.\n   * @example\n   * updateProperty(\"$.meta.default.password\", { meta: { default: { password: \"password\" } } }, \"new-password\")\n   * // Output: { meta: { default: { password: \"new-password\" } } }\n   */\n  updateProperty(path: string, json: Criteria<T>, value: any): any {\n    if (!path?.includes(\"$.\") && isObject(json)) {\n      (json as CriteriaObject)[path] = value;\n      return json;\n    }\n\n    return JSONPath({\n      path,\n      json: json as Criteria,\n      wrap: false,\n      callback: (_: any, __: any, { parent, parentProperty }: any) => {\n        return (parent[parentProperty] = value);\n      },\n    });\n  }\n\n  /**\n   * Resolves the text properties of a string for a single object.\n   * @param str The string containing path expressions\n   * @param criteria The object to resolve paths against\n   */\n  resolveTextPathExpressions(str: string, criteria: CriteriaObject<T>): string;\n\n  /**\n   * Resolves the text properties of a string for an array.\n   * @param str The string containing path expressions\n   * @param criteria The array to resolve paths against\n   */\n  resolveTextPathExpressions(str: string, criteria: Array<T>): string;\n\n  /**\n   * Resolves the text properties of a string.\n   * @param {string} str\n   * @param {Criteria} criteria\n   * @returns {string} The resolved string.\n   * @example\n   * resolveTextProperties(\n   *  \"Password is invalid and contains username($.username), name($.name) and family($.family)\",\n   *  {\n   *  meta: { default: { password: \"@john-doe-@johndoe\" } },\n   *  username: \"john-doe\",\n   *  name: \"john\",\n   *  family: \"doe\",\n   * }) // Output: \"Password is invalid and contains username(john-doe), name(john) and family(doe)\"\n   */\n  resolveTextPathExpressions(str: string, criteria: Criteria<T>): string {\n    const expressions = extractJsonPathExpressions(str);\n    let result = str;\n\n    for (const expression of expressions) {\n      const resolvedExpressionPath = (this as any).resolveProperty(\n        expression,\n        criteria,\n      );\n      result = result.replace(expression, resolvedExpressionPath);\n    }\n\n    return result;\n  }\n}\n"
  },
  {
    "path": "packages/core/src/services/rule-engine.ts",
    "content": "import { Validator } from \"@root/services/validator\";\nimport { Evaluator } from \"@root/services/evaluator\";\nimport { Mutator } from \"@root/services/mutator\";\nimport { Introspector } from \"@root/services/introspector\";\nimport { RuleBuilder } from \"@root/services/builder\";\nimport { operatorRegistry, initializeOperators } from \"@root/operators/factory\";\nimport type {\n  RuleType,\n  EvaluationResult,\n  CriteriaObject,\n  Criteria,\n} from \"@root/types\";\nimport type { EnhancedIntrospectionResult } from \"./introspector\";\n\n/**\n * Configuration options for RuleEngineV2\n */\nexport interface RuleEngineConfig {\n  /**\n   * Whether to skip validation for trusted rules\n   */\n  trustMode?: boolean;\n\n  /**\n   * Whether to initialize built-in operators automatically\n   */\n  autoInitializeOperators?: boolean;\n\n  /**\n   * Custom operator initialization function\n   */\n  customOperatorInit?: () => void;\n\n  /**\n   * Enable performance optimizations\n   */\n  enableOptimizations?: boolean;\n\n  /**\n   * Cache evaluation results\n   */\n  enableCaching?: boolean;\n\n  /**\n   * Maximum cache size\n   */\n  maxCacheSize?: number;\n}\n\n/**\n * Enhanced Rule Engine with Strategy pattern and improved type safety\n */\nexport class RuleEngine {\n  private static instance: RuleEngine;\n  private readonly validator = new Validator();\n  private readonly evaluator = new Evaluator();\n  private readonly mutator = new Mutator();\n  private readonly introspector = new Introspector();\n  private config: RuleEngineConfig = {};\n  private cache?: Map<string, any>;\n  private initialized = false;\n\n  /**\n   * Private constructor for singleton pattern\n   */\n  private constructor(config?: RuleEngineConfig) {\n    this.configure(config);\n  }\n\n  /**\n   * Get singleton instance\n   */\n  static getInstance(config?: RuleEngineConfig): RuleEngine {\n    if (!RuleEngine.instance) {\n      RuleEngine.instance = new RuleEngine(config);\n    }\n    return RuleEngine.instance;\n  }\n\n  /**\n   * Configure the rule engine\n   */\n  configure(config?: RuleEngineConfig): void {\n    this.config = {\n      autoInitializeOperators: true,\n      enableOptimizations: true,\n      ...config,\n    };\n\n    // Initialize operators if needed\n    if (!this.initialized && this.config.autoInitializeOperators) {\n      initializeOperators();\n      this.initialized = true;\n    }\n\n    // Run custom initialization if provided\n    if (this.config.customOperatorInit) {\n      this.config.customOperatorInit();\n    }\n\n    // Setup caching if enabled\n    if (this.config.enableCaching) {\n      this.cache = new Map();\n    }\n  }\n\n  /**\n   * Evaluates a rule against a single criteria object and returns a single result.\n   * @param rule The rule to evaluate\n   * @param criteria The criteria object to evaluate against\n   * @param trustRule Whether to skip validation\n   */\n  async evaluate<T = any>(\n    rule: RuleType,\n    criteria: CriteriaObject<T>,\n    trustRule?: boolean,\n  ): Promise<EvaluationResult<T>>;\n\n  /**\n   * Evaluates a rule against an array of criteria and returns an array of results.\n   * @param rule The rule to evaluate\n   * @param criteria The array of criteria to evaluate against\n   * @param trustRule Whether to skip validation\n   */\n  async evaluate<T = any>(\n    rule: RuleType,\n    criteria: Array<T>,\n    trustRule?: boolean,\n  ): Promise<Array<EvaluationResult<T>>>;\n\n  /**\n   * Evaluates a rule against given criteria\n   * @param rule The rule to evaluate\n   * @param criteria The criteria to test against\n   * @param trustRule Whether to skip validation\n   */\n  async evaluate<T = any>(\n    rule: RuleType,\n    criteria: Criteria,\n    trustRule?: boolean,\n  ): Promise<EvaluationResult<T> | Array<EvaluationResult<T>>> {\n    // Validate unless in trust mode\n    if (!trustRule && !this.config.trustMode) {\n      const validation = this.validator.validate(rule);\n      if (!validation.isValid) {\n        throw validation;\n      }\n    }\n\n    // Check cache if enabled\n    if (this.config.enableCaching && this.cache) {\n      const cacheKey = this.getCacheKey(rule, criteria);\n      if (this.cache.has(cacheKey)) {\n        return this.cache.get(cacheKey);\n      }\n    }\n\n    // Apply mutations if any\n    const mutatedCriteria = await this.mutator.mutate(criteria);\n\n    // Evaluate the rule\n    const result = this.evaluator.evaluate(rule, mutatedCriteria);\n\n    // Cache result if enabled\n    if (this.config.enableCaching && this.cache) {\n      const cacheKey = this.getCacheKey(rule, criteria);\n      this.cache.set(cacheKey, result);\n\n      // Manage cache size\n      if (\n        this.config.maxCacheSize &&\n        this.cache.size > this.config.maxCacheSize\n      ) {\n        const firstKey = this.cache.keys().next().value;\n        this.cache.delete(firstKey!);\n      }\n    }\n\n    return result;\n  }\n\n  /**\n   * Quick check if a rule passes for a single criteria object\n   */\n  async checkIsPassed(\n    rule: RuleType,\n    criteria: CriteriaObject,\n    trustRule?: boolean,\n  ): Promise<boolean>;\n\n  /**\n   * Quick check if a rule passes for an array of criteria\n   * Returns single boolean if all pass/fail uniformly, otherwise array of booleans\n   */\n  async checkIsPassed<T = any>(\n    rule: RuleType,\n    criteria: Array<T>,\n    trustRule?: boolean,\n  ): Promise<boolean | boolean[]>;\n\n  /**\n   * Quick check if a rule passes for given criteria\n   * When criteria is an array and all pass, returns true\n   * When criteria is an array and any fail, returns false\n   */\n  async checkIsPassed(\n    rule: RuleType,\n    criteria: Criteria,\n    trustRule?: boolean,\n  ): Promise<boolean | boolean[]> {\n    const result = await this.evaluate(rule, criteria, trustRule);\n\n    if (Array.isArray(result)) {\n      // If all criteria pass, return true, otherwise return array of results\n      const allPassed = result.every((r) => r.isPassed);\n      return result.length === 1 || allPassed\n        ? allPassed\n        : result.map((r) => r.isPassed);\n    }\n\n    return result.isPassed;\n  }\n\n  /**\n   * Get just the evaluation result value for a single criteria\n   */\n  async getEvaluateResult<T = any>(\n    rule: RuleType,\n    criteria: CriteriaObject,\n    trustRule?: boolean,\n  ): Promise<T>;\n\n  /**\n   * Get just the evaluation result values for an array of criteria\n   */\n  async getEvaluateResult<T = any>(\n    rule: RuleType,\n    criteria: Array<any>,\n    trustRule?: boolean,\n  ): Promise<T[]>;\n\n  /**\n   * Get just the evaluation result value\n   */\n  async getEvaluateResult<T = any>(\n    rule: RuleType,\n    criteria: Criteria,\n    trustRule?: boolean,\n  ): Promise<T | T[]> {\n    const result = await this.evaluate(rule, criteria, trustRule);\n\n    if (Array.isArray(result)) {\n      return result.map((r) => r.value);\n    }\n\n    return result.value;\n  }\n\n  /**\n   * Evaluate multiple rules against a single criteria object\n   */\n  async evaluateMany<T = any>(\n    rules: RuleType[],\n    criteria: CriteriaObject<T>,\n    trustRule?: boolean,\n  ): Promise<Array<EvaluationResult<T>>>;\n\n  /**\n   * Evaluate multiple rules against an array of criteria\n   */\n  async evaluateMany<T = any>(\n    rules: RuleType[],\n    criteria: Array<T>,\n    trustRule?: boolean,\n  ): Promise<Array<Array<EvaluationResult<T>>>>;\n\n  /**\n   * Evaluate multiple rules against the same criteria\n   */\n  async evaluateMany<T = any>(\n    rules: RuleType[],\n    criteria: Criteria,\n    trustRule?: boolean,\n  ): Promise<Array<EvaluationResult<T>> | Array<Array<EvaluationResult<T>>>> {\n    if (Array.isArray(criteria)) {\n      // When criteria is an array, each rule gets evaluated against the array\n      const results = await Promise.all(\n        rules.map((rule) => this.evaluate<T>(rule, criteria, trustRule)),\n      );\n      return results as Array<Array<EvaluationResult<T>>>;\n    } else {\n      // When criteria is a single object, each rule gets evaluated against it\n      const results = await Promise.all(\n        rules.map((rule) => this.evaluate<T>(rule, criteria, trustRule)),\n      );\n      return results as Array<EvaluationResult<T>>;\n    }\n  }\n\n  /**\n   * Introspect a rule to understand its structure and requirements\n   */\n  introspect<R = any>(\n    rule: RuleType<R>,\n    options?: {\n      includeMetadata?: boolean;\n      includeComplexity?: boolean;\n      validateOperators?: boolean;\n    },\n  ): EnhancedIntrospectionResult<R> {\n    // Validate the rule first\n    const validation = this.validator.validate(rule);\n    if (!validation.isValid) {\n      throw validation;\n    }\n\n    return this.introspector.introspect(rule, options);\n  }\n\n  /**\n   * Validate a rule\n   */\n  validate(rule: RuleType): ReturnType<Validator[\"validate\"]> {\n    return this.validator.validate(rule);\n  }\n\n  /**\n   * Validate operators in a rule\n   */\n  validateOperators(rule: RuleType): { isValid: boolean; errors: string[] } {\n    return this.introspector.validateOperators(rule);\n  }\n\n  /**\n   * Get all operators used in a rule\n   */\n  getUsedOperators(rule: RuleType): Set<string> {\n    return this.introspector.getUsedOperators(rule);\n  }\n\n  /**\n   * Create a rule builder\n   */\n  builder(): RuleBuilder {\n    return new RuleBuilder(this.validator);\n  }\n\n  /**\n   * Register mutations\n   */\n  registerMutation(field: string, mutation: (value: any) => any): void {\n    this.mutator.add(field, mutation);\n  }\n\n  /**\n   * Add mutation (backward compatibility)\n   */\n  addMutation(field: string, mutation: (value: any) => any): void {\n    this.registerMutation(field, mutation);\n  }\n\n  /**\n   * Remove mutation (backward compatibility)\n   */\n  removeMutation(field: string): void {\n    this.mutator.remove(field);\n  }\n\n  /**\n   * Clear mutation cache\n   */\n  clearMutationCache(field?: string): void {\n    this.mutator.clearCache(field);\n  }\n\n  /**\n   * Clear all mutations\n   */\n  clearMutations(): void {\n    this.mutator.removeAll();\n  }\n\n  /**\n   * Clear evaluation cache\n   */\n  clearCache(): void {\n    this.cache?.clear();\n  }\n\n  /**\n   * Get operator registry for advanced usage\n   */\n  getOperatorRegistry() {\n    return operatorRegistry;\n  }\n\n  /**\n   * Generate cache key for rule and criteria\n   */\n  private getCacheKey(rule: RuleType, criteria: Criteria): string {\n    return JSON.stringify({ rule, criteria });\n  }\n\n  // Static convenience methods\n  /**\n   * Static method: Evaluates a rule against a single criteria object\n   */\n  static async evaluate<T = any>(\n    rule: RuleType,\n    criteria: CriteriaObject<T>,\n    trustRule?: boolean,\n  ): Promise<EvaluationResult<T>>;\n\n  /**\n   * Static method: Evaluates a rule against an array of criteria\n   */\n  static async evaluate<T = any>(\n    rule: RuleType,\n    criteria: Array<T>,\n    trustRule?: boolean,\n  ): Promise<Array<EvaluationResult<T>>>;\n\n  /**\n   * Static method: Evaluates a rule against criteria\n   */\n  static async evaluate<T = any>(\n    rule: RuleType,\n    criteria: Criteria,\n    trustRule?: boolean,\n  ): Promise<EvaluationResult<T> | Array<EvaluationResult<T>>> {\n    return RuleEngine.getInstance().evaluate(rule, criteria, trustRule);\n  }\n\n  /**\n   * Static method: Quick check if a rule passes for a single criteria\n   */\n  static async checkIsPassed(\n    rule: RuleType,\n    criteria: CriteriaObject,\n    trustRule?: boolean,\n  ): Promise<boolean>;\n\n  /**\n   * Static method: Quick check if a rule passes for an array of criteria\n   */\n  static async checkIsPassed<T = any>(\n    rule: RuleType,\n    criteria: Array<T>,\n    trustRule?: boolean,\n  ): Promise<boolean | boolean[]>;\n\n  /**\n   * Static method: Quick check if a rule passes\n   */\n  static async checkIsPassed(\n    rule: RuleType,\n    criteria: Criteria,\n    trustRule?: boolean,\n  ): Promise<boolean | boolean[]> {\n    return RuleEngine.getInstance().checkIsPassed(rule, criteria, trustRule);\n  }\n\n  /**\n   * Static method: Get evaluation result value for a single criteria\n   */\n  static async getEvaluateResult<T = any>(\n    rule: RuleType,\n    criteria: CriteriaObject,\n    trustRule?: boolean,\n  ): Promise<T>;\n\n  /**\n   * Static method: Get evaluation result values for an array of criteria\n   */\n  static async getEvaluateResult<T = any>(\n    rule: RuleType,\n    criteria: Array<any>,\n    trustRule?: boolean,\n  ): Promise<T[]>;\n\n  /**\n   * Static method: Get evaluation result value\n   */\n  static async getEvaluateResult<T = any>(\n    rule: RuleType,\n    criteria: Criteria,\n    trustRule?: boolean,\n  ): Promise<T | T[]> {\n    return RuleEngine.getInstance().getEvaluateResult(\n      rule,\n      criteria,\n      trustRule,\n    );\n  }\n\n  static introspect<R = any>(\n    rule: RuleType<R>,\n    options?: {\n      includeMetadata?: boolean;\n      includeComplexity?: boolean;\n      validateOperators?: boolean;\n    },\n  ): EnhancedIntrospectionResult<R> {\n    return RuleEngine.getInstance().introspect(rule, options);\n  }\n\n  static validate(rule: RuleType): ReturnType<Validator[\"validate\"]> {\n    return RuleEngine.getInstance().validate(rule);\n  }\n\n  static builder(): RuleBuilder {\n    return RuleEngine.getInstance().builder();\n  }\n\n  // Static mutation methods for backward compatibility\n  static addMutation(field: string, mutation: (value: any) => any): void {\n    RuleEngine.getInstance().addMutation(field, mutation);\n  }\n\n  static removeMutation(field: string): void {\n    RuleEngine.getInstance().removeMutation(field);\n  }\n\n  static clearMutationCache(field?: string): void {\n    RuleEngine.getInstance().clearMutationCache(field);\n  }\n}\n"
  },
  {
    "path": "packages/core/src/services/validator.ts",
    "content": "import { isEmpty } from \"ramda\";\nimport { RuleError, isObject } from \"@root/utils\";\nimport { isStringOperator } from \"@root/operators\";\nimport { operatorRegistry } from \"@root/operators/registry\";\nimport { ObjectDiscovery } from \"@root/services/object-discovery\";\n// Enums\nimport { Operators, ConditionTypes } from \"@root/enums\";\n// Types\nimport type {\n  ValidationResult,\n  RuleType,\n  OperatorsType,\n  Constraint,\n  ConditionType,\n  Condition,\n} from \"@root/types\";\n\nexport class Validator<T = any> {\n  private readonly discovery = new ObjectDiscovery<T>();\n\n  /**\n   * Validates a rule and returns a boolean indicating its validity.\n   *\n   * This function checks whether a provided rule object adheres to the expected\n   * format and data types.\n   * If the rule is valid, it returns `true`.\n   * Otherwise, a `RuleError` object is returned containing details about the validation issue.\n   *\n   * The `RuleError` object has the following properties:\n   *   - `message` (string): A descriptive message explaining the validation error.\n   *   - `element` (*): The specific element within the rule that caused the error.\n   *                   The type of `element` can vary depending on the structure of\n   *                   your rule object.\n   *\n   * @param {object} rule - The rule object to be validated.\n   *\n   * @returns {boolean|object} True if the rule is valid, a `RuleError` object\n   *                            with details on the validation error otherwise.\n   *                            The `RuleError` object has the following properties:\n   *                            - `message` (string): A descriptive message explaining the validation error.\n   *                            - `element` (*): The specific element within the rule that caused the error.\n   *                            The type of `element` can vary depending on the structure of your rule object.\n   *                            If the rule is valid, the function returns `true`.\n   */\n  validate(rule: RuleType<T>): RuleError {\n    // Assume the rule is valid.\n    const result: ValidationResult = { isValid: true };\n\n    // Check the rule is a valid JSON\n    if (!isObject(rule)) {\n      return new RuleError({\n        isValid: false,\n        error: {\n          message: \"The rule must be a valid JSON object.\",\n          element: rule,\n        },\n      });\n    }\n\n    // Cater for the case where the condition property is not an array.\n    const conditions = this.discovery.getConditions(rule);\n\n    // Validate the 'conditions' property.\n    if (\n      !conditions.length ||\n      (isObject(conditions[0]) && isEmpty(conditions[0]))\n    ) {\n      return new RuleError({\n        isValid: false,\n        error: {\n          message:\n            \"The conditions property must contain at least one condition.\",\n          element: rule,\n        },\n      });\n    }\n\n    // Validate each condition in the rule.\n    for (const condition of conditions) {\n      const subResult = this.validateCondition(condition);\n      result.isValid = result.isValid && subResult.isValid;\n      result.error = (result?.error ?? subResult?.error)!;\n    }\n\n    return new RuleError({\n      isValid: result.isValid,\n      error: {\n        message: result.error?.message ?? \"\",\n        element: result.error?.element ?? {},\n      },\n    });\n  }\n\n  /**\n   * Validates the structure and data types of a condition object.\n   *\n   * This function ensures the condition object adheres to the expected format\n   * and data types.\n   * It checks for the presence of essential properties (`field`,`operator`, and `value`) and validates their data types.\n   * Additionally, it verifies compatibility between the operator and the value format.\n   *\n   * The function supports nested conditions through recursive validation.\n   * The `depth` parameter is used to track the current recursion level and prevent infinite loops.\n   *\n   * @param {object} condition - The condition object to be validated.\n   * @param {string} condition.field - The field name to be evaluated.\n   * @param {string} condition.operator - The comparison operator to be used.\n   * @param {string | number | boolean | Array} condition.value - The value to be compared against the field.\n   * @param {number} [depth] - Optional recursion depth parameter (defaults to 0).\n   *\n   * @returns {object} A `RuleError` object with the following properties:\n   *   - `isValid` (boolean): True if the condition is valid, False otherwise.\n   *   - `error` (string|null): An error message describing the validation issue,\n   *                             or null if the condition is valid.\n   *                             The error message is set to the first validation error encountered.\n   *                             If the condition is valid, the error message is null.\n   */\n  private validateCondition(\n    condition: Condition,\n    depth: number = 0,\n  ): RuleError {\n    // Check to see if the condition is valid.\n    const result = this.isValidCondition(condition);\n    if (!result.isValid) {\n      return result;\n    }\n\n    // Set the type of condition.\n    const type = this.discovery.conditionType(condition) as ConditionType;\n\n    // Check if the condition is iterable\n    if (!Array.isArray(condition[type])) {\n      return new RuleError({\n        isValid: false,\n        error: {\n          message: `The condition '${type}' should be iterable.`,\n          element: condition,\n        },\n      });\n    }\n\n    // Validate each item in the condition.\n    for (const node of condition[type]) {\n      const isCondition = this.discovery.isCondition(node);\n      if (isCondition) {\n        const subResult = this.validateCondition(node as Condition, depth + 1);\n        result.isValid = result.isValid && subResult.isValid;\n        result.error = result?.error ?? subResult?.error;\n      }\n\n      const isConstraint = this.discovery.isConstraint(node);\n      if (isConstraint) {\n        const subResult = this.validateConstraint(node as Constraint);\n        result.isValid = result.isValid && subResult.isValid;\n        result.error = result.error ?? subResult.error;\n      }\n\n      if (!isConstraint && !isCondition) {\n        return new RuleError({\n          isValid: false,\n          error: {\n            message: \"Each node should be a condition or constraint.\",\n            element: node,\n          },\n        });\n      }\n\n      // If any part fails validation, there is no point to continue.\n      if (!result.isValid) {\n        break;\n      }\n    }\n\n    return new RuleError({\n      isValid: result.isValid,\n      error: {\n        message: result.error?.message ?? \"\",\n        element: result.error?.element ?? {},\n      },\n    });\n  }\n\n  /**\n   * Validates the structure and data types of a rule constraint.\n   *\n   * This function ensures that a rule constraint object adheres to the expected format\n   * and data types for its properties.\n   * It verifies the presence of essential fields (`field`, `operator`, and `value`),\n   * validates their data types, and checks for compatibility between the operator and value format.\n   *\n   * @param {object} constraint - The rule constraint object to be validated.\n   * @param {string} constraint.field - The field name to be evaluated.\n   * @param {string} constraint.operator - The comparison operator to be used.\n   * @param {string | number | boolean | Array} constraint.value - The value to be compared against the field.\n   *\n   * @returns {object} A `RuleError` object with the following properties:\n   *   - `isValid` (boolean): True if the constraint is valid, False otherwise.\n   *   - `error` (string|null): An error message describing the validation issue,\n   *                             or null if the constraint is valid.\n   */\n  private validateConstraint(constraint: Constraint): RuleError {\n    if (!isStringOperator(constraint.field)) {\n      return new RuleError({\n        isValid: false,\n        error: {\n          message: 'Constraint \"field\" must be of type string.',\n          element: constraint,\n        },\n      });\n    }\n\n    const matchOperators: Array<OperatorsType> = [\n      Operators.Matches,\n      Operators.NotMatches,\n    ];\n\n    // Check if the operator exists in the registry\n    if (!operatorRegistry.has(constraint.operator as OperatorsType)) {\n      const registeredOperators = operatorRegistry.getOperatorNames();\n      return new RuleError({\n        isValid: false,\n        error: {\n          message: `Constraint \"operator\" with value ${constraint.operator} is invalid. Valid operators are ${registeredOperators.join(`,`)}`,\n          element: constraint,\n        },\n      });\n    }\n\n    // We must check that the value is an array if the operator is 'in' or 'not in'.\n    const arrayOperatorsChecklist = [\n      Operators.In,\n      Operators.NotIn,\n      Operators.ContainsAny,\n      Operators.NotContainsAny,\n      Operators.ContainsAll,\n      Operators.NotContainsAll,\n    ];\n    if (\n      arrayOperatorsChecklist.includes(constraint.operator) &&\n      !Array.isArray(constraint.value)\n    ) {\n      return new RuleError({\n        isValid: false,\n        error: {\n          message: `Constraint \"value\" must be an array if the \"operator\" is in ${arrayOperatorsChecklist.join(\",\")}`,\n          element: constraint,\n        },\n      });\n    }\n\n    if (matchOperators.includes(constraint.operator)) {\n      try {\n        new RegExp(constraint.value as string);\n      } catch {\n        return new RuleError({\n          isValid: false,\n          error: {\n            message: `Constraint \"value\" must be a valid regular expression if the \"operator\" is in ${matchOperators.join(\",\")}`,\n            element: constraint,\n          },\n        });\n      }\n    }\n\n    return new RuleError({ isValid: true });\n  }\n\n  /**\n   * Checks an object to see if it is a valid condition.\n   * A valid condition must have an 'any', 'all', or 'none' property.\n   * It cannot have more than one.\n   * It must also be an object.\n   * If the object is not a valid condition, a RuleError object is returned.\n   * Otherwise, a RuleError object with a true isValid property is returned.\n   *\n   * @param obj The object to check.\n   * @returns {RuleError} A RuleError object.\n   */\n  private isValidCondition(obj: any): RuleError {\n    if (!this.discovery.isCondition(obj)) {\n      return new RuleError({\n        isValid: false,\n        error: {\n          message: \"Invalid condition structure.\",\n          element: obj,\n        },\n      });\n    }\n\n    const isAny = ConditionTypes.OR in obj;\n    const isAll = ConditionTypes.AND in obj;\n    const isNone = ConditionTypes.NONE in obj;\n\n    // A valid condition must have an 'any', 'all', or 'none' property,\n    // but cannot have more than one.\n    if ((isAny && isAll) || (isAny && isNone) || (isAll && isNone)) {\n      return new RuleError({\n        isValid: false,\n        error: {\n          message:\n            'A condition cannot have more than one \"any\", \"all\", or \"none\" property.',\n          element: obj,\n        },\n      });\n    }\n\n    return new RuleError({ isValid: true });\n  }\n}\n"
  },
  {
    "path": "packages/core/src/types/index.ts",
    "content": "export * from \"./introspection.type\";\nexport * from \"./rule.type\";\nexport * from \"./validator.type\";\n"
  },
  {
    "path": "packages/core/src/types/introspection.type.ts",
    "content": "import type { ConditionType } from \"@root/types\";\n\nexport interface IntrospectionStepChange {\n  key: string;\n  value: unknown;\n}\n\nexport interface IntrospectionStep {\n  parentType?: ConditionType;\n  currType: ConditionType;\n  depth: number;\n  option: Record<string, unknown>;\n  changes?: Array<IntrospectionStepChange>;\n}\n"
  },
  {
    "path": "packages/core/src/types/rule.type.ts",
    "content": "// Enums\nimport type { Operators, ConditionTypes } from \"@root/enums\";\n\nexport type ConditionType =\n  | ConditionTypes.OR\n  | ConditionTypes.AND\n  | ConditionTypes.NONE;\nexport type OperatorsType =\n  | Operators.Equals\n  | Operators.NotEquals\n  | Operators.GreaterThan\n  | Operators.LessThan\n  | Operators.GreaterThanOrEquals\n  | Operators.LessThanOrEquals\n  | Operators.Like\n  | Operators.NotLike\n  | Operators.StartsWith\n  | Operators.EndsWith\n  | Operators.ContainsString\n  | Operators.In\n  | Operators.NotIn\n  | Operators.Contains\n  | Operators.NotContains\n  | Operators.ContainsAny\n  | Operators.SelfContainsAny\n  | Operators.NotContainsAny\n  | Operators.SelfContainsNone\n  | Operators.SelfNotContainsAny\n  | Operators.ContainsAll\n  | Operators.SelfContainsAll\n  | Operators.NotContainsAll\n  | Operators.SelfNotContainsAll\n  | Operators.Matches\n  | Operators.NotMatches\n  | Operators.Exists\n  | Operators.NotExists\n  | Operators.NullOrUndefined\n  | Operators.NotNullOrUndefined\n  | Operators.Empty\n  | Operators.NotEmpty\n  | Operators.DateAfter\n  | Operators.DateAfterNow\n  | Operators.DateBefore\n  | Operators.DateBeforeNow\n  | Operators.DateAfterOrEquals\n  | Operators.DateAfterNowOrEquals\n  | Operators.DateBeforeOrEquals\n  | Operators.DateBeforeNowOrEquals\n  | Operators.DateEquals\n  | Operators.DateEqualsToNow\n  | Operators.DateNotEquals\n  | Operators.DateNotEqualsToNow\n  | Operators.DateBetween\n  | Operators.DateNotBetween\n  | Operators.TimeAfter\n  | Operators.TimeBefore\n  | Operators.TimeAfterOrEquals\n  | Operators.TimeBeforeOrEquals\n  | Operators.TimeEquals\n  | Operators.TimeNotEquals\n  | Operators.TimeBetween\n  | Operators.TimeNotBetween\n  | Operators.NullOrWhiteSpace\n  | Operators.NotNullOrWhiteSpace\n  | Operators.Numeric\n  | Operators.NotNumeric\n  | Operators.Boolean\n  | Operators.NotBoolean\n  | Operators.Date\n  | Operators.NotDate\n  | Operators.Email\n  | Operators.NotEmail\n  | Operators.Url\n  | Operators.NotUrl\n  | Operators.UUID\n  | Operators.NotUUID\n  | Operators.Alpha\n  | Operators.NotAlpha\n  | Operators.AlphaNumeric\n  | Operators.NotAlphaNumeric\n  | Operators.PersianAlpha\n  | Operators.NotPersianAlpha\n  | Operators.PersianAlphaNumeric\n  | Operators.NotPersianAlphaNumeric\n  | Operators.LowerCase\n  | Operators.NotLowerCase\n  | Operators.UpperCase\n  | Operators.NotUpperCase\n  | Operators.String\n  | Operators.NotString\n  | Operators.Object\n  | Operators.NotObject\n  | Operators.Array\n  | Operators.NotArray\n  | Operators.ArrayLength\n  | Operators.ArrayMinLength\n  | Operators.ArrayMaxLength\n  | Operators.BooleanString\n  | Operators.NotBooleanString\n  | Operators.BooleanNumber\n  | Operators.NotBooleanNumber\n  | Operators.BooleanNumberString\n  | Operators.NotBooleanNumberString\n  | Operators.Number\n  | Operators.NotNumber\n  | Operators.Integer\n  | Operators.NotInteger\n  | Operators.Float\n  | Operators.NotFloat\n  | Operators.Positive\n  | Operators.NotPositive\n  | Operators.Negative\n  | Operators.NotNegative\n  | Operators.Zero\n  | Operators.NotZero\n  | Operators.Min\n  | Operators.NotMin\n  | Operators.Max\n  | Operators.NotMax\n  | Operators.Between\n  | Operators.NotBetween\n  | Operators.NumberBetween\n  | Operators.NotNumberBetween\n  | Operators.StringLength\n  | Operators.NotStringLength\n  | Operators.MinLength\n  | Operators.NotMinLength\n  | Operators.MaxLength\n  | Operators.NotMaxLength\n  | Operators.LengthBetween\n  | Operators.NotLengthBetween\n  | Operators.Falsy\n  | Operators.NotFalsy\n  | Operators.Truthy\n  | Operators.NotTruthy;\n\nexport interface Constraint {\n  /**\n   * The field to evaluate.\n   * @example \"name\"\n   * @example \"age\"\n   * @example \"$.meta.default.password\"\n   * @example \"$.foo[0].bar\"\n   */\n  field: string;\n  /**\n   * The operator to use for the evaluation.\n   * @example Operators.Equals\n   */\n  operator: OperatorsType;\n  /**\n   * The value to compare against the field.\n   * @example \"test\"\n   * @example 5\n   * @example true\n   * @example { name: \"test\" }\n   * @example [\"test\", 5, true, { name: \"test\" }]\n   * @example [\"$.username\", \"$.name\", \"$.family\"]\n   */\n  value?:\n    | string\n    | number\n    | boolean\n    | Record<string, unknown>\n    | Array<string | number | boolean | Record<string, unknown>>;\n  /**\n   * The message to display if the constraint is invalid. This is optional and only used if the constraint is invalid.\n   * @default \"The constraint is invalid.\"\n   * @example \"The field must be a string.\"\n   * @example \"The field must be a number.\"\n   * @example \"The field must be a boolean.\"\n   * @example \"The field must be an object.\"\n   */\n  message?: string;\n}\n\n/**\n * The result of the evaluation.\n * This is the value of the field that was evaluated.\n * - If the field is valid, then the `isPassed` property is `true`.\n * - If the field is invalid, then the `isPassed` property is `false`.\n * - The `message` property is optional and only used if the field is invalid.\n *\n * @example { value: \"The field is valid.\" }\n * @example { value: \"The field is invalid.\", isPassed: false }\n * @example { value: \"The field is invalid.\", isPassed: false, message: \"The field must be a string.\" }\n */\nexport interface EvaluationResult<T = any> {\n  // The value of the field that was evaluated. This is the result of the evaluation.\n  value: T;\n  // If the field is valid, then the `isPassed` property is `true`. If the field is invalid, then the `isPassed` property is `false`.\n  // The engine fills this field. Do not set it manually.\n  isPassed: boolean;\n  // The message to display if the field is invalid. This is optional and only used if the field is invalid.\n  message?: string;\n}\nexport type EngineResult<T = any> = Omit<EvaluationResult<T>, \"isPassed\">;\nexport type CriteriaObject<T = any> = Record<string, T>;\nexport type Criteria<T = any> = CriteriaObject<T> | Array<T>;\n\nexport interface Condition<R = any> {\n  /**\n   * The constraints to evaluate. This is optional.\n   * - If one of the constraints is met, then the result is valid.\n   * @example { or: [{ field: \"name\", operator: Operators.Equals, value: \"test\" }] } // The result is valid if the name field equals \"test\".\n   */\n  or?: Array<Constraint | Condition<R>>;\n  /**\n   * The constraints to evaluate. This is optional.\n   * - If all the constraints are met, then the result is valid.\n   * @example { and: [{ field: \"name\", operator: Operators.Equals, value: \"test\" }] } // The result is valid if the name field equals \"test\".\n   */\n  and?: Array<Constraint | Condition<R>>;\n  /**\n   * The constraints to evaluate. This is optional.\n   * - If none of the constraints are met, then the result is valid.\n   * @example { none: [{ field: \"name\", operator: Operators.Equals, value: \"test\" }] } // The result is valid if the name field does not equal \"test\".\n   */\n  none?: Array<Constraint | Condition<R>>;\n  /**\n   * The result of the evaluation.\n   * - This is the value of the field that was evaluated.\n   * - This is optional.\n   */\n  result?: EngineResult<R>;\n}\n\nexport interface RuleType<R = any> {\n  conditions: Condition<R> | Array<Condition<R>>;\n  // The default result if no conditions are met. This is optional.\n  default?: EngineResult<R>;\n}\n\nexport interface CriteriaRange<R = any> {\n  result: EngineResult<R>;\n  options?: Array<Record<string, unknown>>;\n}\n\nexport interface IntrospectionResult<R = any> {\n  results: Array<CriteriaRange<R>>;\n  default?: EngineResult<R>;\n}\n"
  },
  {
    "path": "packages/core/src/types/validator.type.ts",
    "content": "export interface ValidationResult {\n  isValid: boolean;\n  error?: {\n    message: string;\n    element: object;\n  };\n}\n"
  },
  {
    "path": "packages/core/src/utils/clone.util.ts",
    "content": "export function clone<T>(data: T): T {\n  return structuredClone(data);\n}\n"
  },
  {
    "path": "packages/core/src/utils/date.util.ts",
    "content": "export function getDate(date = new Date()) {\n  return new Date(date.getTime() - date.getTimezoneOffset() * 60000);\n}\n\nexport function dateWithTzOffset(date?: Date) {\n  return getDate(new Date(date?.toISOString() ?? new Date().toISOString()));\n}\n"
  },
  {
    "path": "packages/core/src/utils/error.util.ts",
    "content": "import type { ValidationResult } from \"@root/types\";\n\nexport class RuleError extends Error {\n  constructor(validationResult: ValidationResult) {\n    super(validationResult.error?.message ?? \"\");\n\n    this.error = validationResult.error || null;\n    this.isValid = validationResult.isValid;\n    this.element = validationResult.error?.element || null;\n  }\n\n  /** Indicates whether the rule is valid or not. */\n  isValid: boolean;\n\n  /** The name/type of the error. */\n  type: string = RuleError.name;\n\n  /** The element that caused the error. */\n  element: object | null;\n\n  /** Error */\n  error: ValidationResult[\"error\"] | null;\n\n  toModel?(): ValidationResult {\n    return {\n      isValid: this.isValid,\n      error: {\n        message: this.message,\n        element: this.element as object,\n      },\n    };\n  }\n}\n\nexport class RuleTypeError extends Error {\n  constructor(message: string) {\n    super(message ?? \"The type of rule is not valid for this operation\");\n  }\n\n  /** The name/type of the error. */\n  type: string = RuleError.name;\n}\n"
  },
  {
    "path": "packages/core/src/utils/extract-jsonpath-expressions.util.ts",
    "content": "/**\n * Extracts JSONPath expressions from a given text.\n *\n * @param {string} text - The text containing the expressions.\n * @returns {string[]} - An array of extracted expressions.\n * @example\n * extractJsonPathExpressions(\"The value of $.foo.bar is $['foo']['bar'].\"); // [\"$.foo.bar\", \"$['foo']['bar']\"]\n */\nexport function extractJsonPathExpressions(text: string): Array<string> {\n  // Match complex expressions starting with $ followed by nested structures\n  const regex = /\\$[^\\s,()]+(?:\\[[^[\\]]*\\]|\\([^()]*\\))*/g;\n  const matches: Array<string> = [];\n  let match: RegExpExecArray | null;\n\n  while ((match = regex.exec(text)) !== null) {\n    let expression = match[0];\n    const openParenCount = (expression.match(/\\(/g) || []).length;\n    let closeParenCount = (expression.match(/\\)/g) || []).length;\n    const openBracketCount = (expression.match(/\\[/g) || []).length;\n    let closeBracketCount = (expression.match(/\\]/g) || []).length;\n\n    // Balance closing parentheses\n    while (closeParenCount > openParenCount) {\n      expression = expression.slice(0, expression.lastIndexOf(\")\"));\n      closeParenCount--;\n    }\n\n    // Balance closing brackets\n    while (closeBracketCount > openBracketCount) {\n      expression = expression.slice(0, expression.lastIndexOf(\"]\"));\n      closeBracketCount--;\n    }\n\n    matches.push(expression);\n  }\n\n  return matches;\n}\n"
  },
  {
    "path": "packages/core/src/utils/index.ts",
    "content": "export * from \"./clone.util\";\nexport * from \"./date.util\";\nexport * from \"./error.util\";\nexport * from \"./extract-jsonpath-expressions.util\";\nexport * from \"./is-object.util\";\nexport * from \"./time.util\";\n"
  },
  {
    "path": "packages/core/src/utils/is-object.util.ts",
    "content": "export function kindOf(inp: any): string {\n  return Object.prototype.toString.call(inp).slice(8, -1).toLowerCase();\n}\n\nexport function isObject(inp: any) {\n  return kindOf(inp) === \"object\";\n}\n"
  },
  {
    "path": "packages/core/src/utils/time.util.ts",
    "content": "export function convertTimeToMs(timeString: string) {\n  if (!isValidTime(timeString)) {\n    throw new Error(\"Invalid time format\");\n  }\n\n  const timeParts = timeString.split(\":\");\n  // Extract hours, minutes (required), and optional seconds and milliseconds\n  const [hours, minutes, seconds = 0, milliseconds = 0] = timeParts.map(Number);\n\n  return hours! * 3600000 + minutes! * 60000 + seconds * 1000 + milliseconds;\n}\n\nexport const timeRegex =\n  /^([01]\\d|2[0-3]):([0-5]\\d)(?:[:.]([0-5]\\d)(\\.\\d{1,3})?)?$/;\nexport function isValidTime(timeString: string) {\n  return timeRegex.test(timeString);\n}\n"
  },
  {
    "path": "packages/core/test/builder.spec.ts",
    "content": "import { it, expect, describe } from \"vitest\";\nimport { RuleEngine, Operators, ConditionTypes } from \"@root\";\n\ndescribe(\"builder correctly\", () => {\n  it(\"creates a valid ruleset\", () => {\n    const builder = RuleEngine.builder();\n    expect(\n      RuleEngine.validate(\n        builder\n          .add(\n            builder.condition(ConditionTypes.AND, [\n              builder.constraint(\"field\", Operators.Equals, \"value\"),\n            ]),\n          )\n          .build(),\n      ).isValid,\n    ).toEqual(true);\n  });\n\n  it(\"creates a complex ruleset properly\", () => {\n    const builder = RuleEngine.builder();\n\n    const rule = builder\n      .add(\n        builder.condition(\n          ConditionTypes.AND,\n          [\n            builder.condition(ConditionTypes.OR, [\n              builder.constraint(\"fieldA\", Operators.Equals, \"bar\"),\n              builder.constraint(\"fieldB\", Operators.GreaterThanOrEquals, 2),\n            ]),\n            builder.constraint(\"fieldC\", Operators.NotIn, [1, 2, 3]),\n          ],\n          {\n            value: 3,\n          },\n        ),\n      )\n      .add(builder.condition(ConditionTypes.NONE, [], { value: 5 }))\n      .add(\n        builder.condition(ConditionTypes.OR, [\n          builder.constraint(\"fieldA\", Operators.Equals, \"value\"),\n        ]),\n      )\n      .default({ value: 2 })\n      .build(false);\n\n    expect(rule).toEqual({\n      conditions: [\n        {\n          and: [\n            {\n              or: [\n                { field: \"fieldA\", operator: \"equals\", value: \"bar\" },\n                {\n                  field: \"fieldB\",\n                  operator: \"greater-than-or-equals\",\n                  value: 2,\n                },\n              ],\n            },\n            { field: \"fieldC\", operator: \"not-in\", value: [1, 2, 3] },\n          ],\n          result: { value: 3 },\n        },\n        { none: [], result: { value: 5 } },\n        {\n          or: [{ field: \"fieldA\", operator: \"equals\", value: \"value\" }],\n        },\n      ],\n      default: { value: 2 },\n    });\n  });\n});\n"
  },
  {
    "path": "packages/core/test/engine.spec.ts",
    "content": "import { it, expect, describe } from \"vitest\";\nimport type { OperatorsType } from \"@root\";\nimport { RuleError, RuleEngine, Operators } from \"@root\";\n// Assets\nimport { valid1Json } from \"./rulesets/valid1.json\";\nimport { valid2Json } from \"./rulesets/valid2.json\";\nimport { valid3Json } from \"./rulesets/valid3.json\";\nimport { valid5Json } from \"./rulesets/valid5.json\";\nimport { valid13Json } from \"./rulesets/valid13.json\";\nimport { invalid2Json } from \"./rulesets/invalid2.json\";\nimport { Valid10Json } from \"./rulesets/valid10.json\";\nimport {\n  selfFieldsConstraintsJsonWithNoResult,\n  selfFieldsConstraintsJson,\n} from \"./rulesets/self-fields-constraints.json\";\nimport { Valid11Json } from \"./rulesets/valid11.json\";\nimport { valid4Json } from \"./rulesets/valid4.json\";\nimport { RegexRulesJson } from \"./rulesets/regex-rules.json\";\nimport { PasswordRuleJson } from \"./rulesets/password-rule.json\";\n\ndescribe(\"engine works correctly\", () => {\n  it(\"evaluates a simple ruleset\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(valid1Json, {\n        payload: { ProfitPercentage: 9 },\n      }),\n    ).toEqual(false);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid1Json, {\n        payload: { ProfitPercentage: 11 },\n      }),\n    ).toEqual(true);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid1Json, {\n        WinRate: 80,\n        AverageTradeDuration: 5,\n        Duration: 9000000,\n      }),\n    ).toEqual(false);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid1Json, {\n        WinRate: 80,\n        AverageTradeDuration: 5,\n        Duration: 9000000,\n        TotalDaysTraded: 5,\n      }),\n    ).toEqual(true);\n  });\n\n  it(\"evaluates to false if operator is unknown\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(\n        {\n          conditions: [\n            {\n              and: [\n                {\n                  field: \"name\",\n                  operator: \"foo\" as OperatorsType,\n                  value: \"test\",\n                },\n              ],\n            },\n          ],\n        },\n        { name: \"test\" },\n        true,\n      ),\n    ).toEqual(false);\n  });\n\n  it(\"evaluates to false if condition type is unknown\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(\n        {\n          conditions: [\n            {\n              // @ts-ignore\n              any: [\n                { field: \"name\", operator: Operators.Equals, value: \"test\" },\n              ],\n            },\n          ],\n        },\n        { name: \"test\" },\n        true,\n      ),\n    ).toEqual(false);\n  });\n\n  it(\"resolves nested field definitions\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(\n        {\n          conditions: [\n            {\n              and: [\n                {\n                  field: \"$.foo.bar\",\n                  operator: Operators.Equals,\n                  value: \"test\",\n                },\n              ],\n            },\n          ],\n        },\n        {\n          foo: {\n            bar: \"test\",\n          },\n        },\n      ),\n    ).toEqual(true);\n  });\n\n  it(\"handles missing nested field definitions\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(\n        {\n          conditions: [\n            {\n              and: [\n                { field: \"foo.foo\", operator: Operators.Equals, value: \"test\" },\n              ],\n            },\n          ],\n        },\n        {\n          foo: {\n            bar: \"test\",\n          },\n        },\n      ),\n    ).toEqual(false);\n  });\n\n  it(\"handles array of criteria properly\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(\n        {\n          conditions: [\n            {\n              and: [\n                {\n                  field: \"$.foo.bar\",\n                  operator: Operators.Equals,\n                  value: \"bar\",\n                },\n              ],\n            },\n          ],\n        },\n        [\n          {\n            foo: {\n              bar: \"test\",\n            },\n          },\n          {\n            foo: {\n              bar: \"bar\",\n            },\n          },\n          {},\n        ],\n      ),\n    ).toEqual([false, true, false]);\n  });\n\n  it(\"throws an error on invalid not runnable ruleset\", async () => {\n    await expect(\n      async () => await RuleEngine.getEvaluateResult({ conditions: [] }, {}),\n    ).rejects.toThrow(RuleError);\n  });\n\n  it(\"evaluates a simple ruleset with a single condition\", async () => {\n    expect(await RuleEngine.getEvaluateResult(valid13Json, {}, false)).toEqual(\n      2,\n    );\n  });\n\n  it(\"evaluates a nested ruleset\", async () => {\n    expect(await RuleEngine.getEvaluateResult(valid3Json, {})).toEqual(2);\n    expect(\n      await RuleEngine.getEvaluateResult(valid3Json, { Leverage: 1000 }),\n    ).toEqual(3);\n    expect(\n      await RuleEngine.getEvaluateResult(valid3Json, { Leverage: 999 }),\n    ).toEqual(2);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid3Json, { Category: \"Islamic\" }),\n    ).toEqual(4);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid3Json, { Monetization: \"Real\" }),\n    ).toEqual(2);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid3Json, {\n        Monetization: \"Real\",\n        Leverage: 150,\n        CountryIso: \"FI\",\n      }),\n    ).toEqual(3);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid3Json, {\n        Monetization: \"Real\",\n        Leverage: 150,\n        CountryIso: \"FI\",\n        foo: \"bar\",\n        another: false,\n      }),\n    ).toEqual(3);\n  });\n\n  it(\"evaluates invalid rulesets\", async () => {\n    await expect(\n      async () =>\n        await RuleEngine.getEvaluateResult(invalid2Json, { foo: true }, false),\n    ).rejects.toThrow(RuleError);\n\n    await expect(\n      async () =>\n        await RuleEngine.getEvaluateResult(\n          invalid2Json,\n          { Category: \"Islamic\" },\n          false,\n        ),\n    ).rejects.toThrow(RuleError);\n  });\n\n  it(\"evaluates a simple ruleset with none type condition\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(valid2Json, {\n        Leverage: 100,\n        WinRate: 80,\n        AverageTradeDuration: 5,\n        Duration: 9000000,\n        TotalDaysTraded: 5,\n      }),\n    ).toEqual(true);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid2Json, {\n        AverageTradeDuration: 10,\n        Foo: 10,\n      }),\n    ).toEqual(true);\n  });\n\n  it(\"evaluates a simple ruleset with a Contains and ContainsAny any condition\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(valid5Json, {\n        countries: [\"US\", \"FR\"],\n      }),\n    ).toEqual(true);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid5Json, {\n        countries: [\"GB\", \"DE\"],\n      }),\n    ).toEqual(false);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid5Json, { states: [\"CA\", \"TN\"] }),\n    ).toEqual(true);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid5Json, { states: [\"NY\", \"WI\"] }),\n    ).toEqual(false);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid5Json, {\n        states: \"invalid criterion type\",\n      }),\n    ).toEqual(false);\n  });\n\n  it(\"evaluates a self ruleset with a SelfContainsAll and SelfContainsAny\", async () => {\n    expect(\n      await RuleEngine.evaluate(selfFieldsConstraintsJson, {\n        meta: {\n          default: {\n            password: \"@john-doe-@john-doe\",\n          },\n        },\n        username: \"john-doe\",\n        name: \"john\",\n        family: \"doe\",\n      }),\n    ).toEqual({\n      isPassed: false,\n      value: false,\n      message:\n        \"Password is invalid and contains username(john-doe), name(john) and family(doe)\",\n    });\n    expect(\n      await RuleEngine.evaluate(selfFieldsConstraintsJsonWithNoResult, {\n        meta: {\n          default: {\n            password: \"@john-doe-@john-doe\",\n          },\n        },\n        username: \"john-doe\",\n        name: \"john\",\n        family: \"doe\",\n      }),\n    ).toEqual({\n      isPassed: false,\n      value: false,\n      message:\n        \"Password is invalid and contains username(john-doe), name(john) and family(doe)\",\n    });\n\n    expect(\n      await RuleEngine.evaluate(selfFieldsConstraintsJson, {\n        meta: {\n          default: {\n            password: \"@Aa101010@\",\n          },\n        },\n        username: \"john-doe\",\n        name: \"john\",\n        family: \"doe\",\n      }),\n    ).toEqual({\n      isPassed: true,\n      value: true,\n      message:\n        \"Password is valid and contains username(john-doe), name(john) and family(doe)\",\n    });\n\n    expect(\n      await RuleEngine.evaluate(selfFieldsConstraintsJsonWithNoResult, {\n        meta: {\n          default: {\n            password: \"Aa101010@\",\n          },\n        },\n        username: \"john-doe\",\n        name: \"john\",\n        family: \"doe\",\n      }),\n    ).toEqual({\n      isPassed: true,\n      value: true,\n    });\n  });\n\n  it(\"evaluates a simple ruleset with Exists and NotExists conditions\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(Valid10Json, {\n        name: \"John\",\n        age: 20,\n        family: \"Doe\",\n        relationship: \"Father\",\n      }),\n    ).toEqual(false);\n  });\n\n  it(\"evaluates a simple ruleset with Priority based conditions\", async () => {\n    expect(\n      await RuleEngine.evaluate(Valid11Json, {\n        payload: {\n          depositAmount: \"3\",\n        },\n        metadata: {\n          levelId: 1,\n        },\n      }),\n    ).toEqual({\n      isPassed: false,\n      message: \"Deposit amount must be between 4 and 20 characters.\",\n      value: false,\n    });\n  });\n\n  it(\"evaluates a nested ruleset with Priority based conditions\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(valid4Json, {\n        CountryIso: \"GB\",\n        Monetization: \"Real\",\n        Category: 13,\n      }),\n    ).toEqual(2);\n\n    expect(\n      await RuleEngine.getEvaluateResult(valid4Json, {\n        Leverage: 500, // This is the first condition in the ruleset.\n        // It should be evaluated first\n        // and return the result immediately without evaluating the rest of the conditions\n        //\n        // the rest of the conditions are not evaluated\n        // because the first condition is already satisfied\n        CountryIso: \"GB\",\n        Monetization: \"Real\",\n        Category: 22,\n      }),\n    ).toEqual(3);\n  });\n\n  it(\"evaluates a nested regex ruleset\", async () => {\n    expect(\n      await RuleEngine.evaluate(RegexRulesJson, {\n        payload: {\n          password: \"@a101010\",\n        },\n        data: {\n          username: \"51c351351\",\n        },\n      }),\n    ).toEqual({\n      isPassed: false,\n      value: false,\n      message: \"رمزعبور باید حداقل شامل یک حرف بزرگ باشد\",\n    });\n\n    expect(\n      await RuleEngine.evaluate(RegexRulesJson, {\n        payload: {\n          password: \"@A101010\",\n        },\n        data: {\n          username: \"51c351351\",\n        },\n      }),\n    ).toEqual({\n      isPassed: false,\n      value: false,\n      message: \"رمزعبور باید حداقل شامل یک حرف کوچک باشد\",\n    });\n\n    expect(\n      await RuleEngine.evaluate(RegexRulesJson, {\n        payload: {\n          password: \"Aa101010\",\n        },\n        data: {\n          username: \"51c351351\",\n        },\n      }),\n    ).toEqual({\n      isPassed: false,\n      value: false,\n      message: \"رمزعبور باید حداقل شامل یک کاراکتر خاص باشد\",\n    });\n\n    expect(\n      await RuleEngine.evaluate(RegexRulesJson, {\n        payload: {\n          password: \"@Aaaaaaaaaa\",\n        },\n        data: {\n          username: \"51c351351\",\n        },\n      }),\n    ).toEqual({\n      isPassed: false,\n      value: false,\n      message: \"رمزعبور باید حداقل شامل یک عدد باشد\",\n    });\n  });\n\n  it(\"evaluates a simple password ruleset\", async () => {\n    expect(\n      await RuleEngine.evaluate(PasswordRuleJson, {\n        payload: {\n          password: \"@Aa101010\",\n        },\n        data: {\n          phone: \"09022002580\",\n        },\n      }),\n    ).toEqual({\n      isPassed: true,\n      value: true,\n    });\n  });\n\n  it(\"resolve constraints message in and condition\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(\n        {\n          conditions: [\n            {\n              // @ts-ignore\n              and: [\n                {\n                  field: \"name\",\n                  operator: Operators.Equals,\n                  value: \"test\",\n                  message: \"name should be test\",\n                },\n              ],\n            },\n          ],\n        },\n        { name: \"test2\" },\n        true,\n      ),\n    ).toEqual(false);\n  });\n\n  it(\"evaluate a none condition\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(\n        {\n          conditions: [\n            {\n              none: [\n                {\n                  field: \"name\",\n                  operator: Operators.Equals,\n                  value: \"test\",\n                  message: \"name should be test\",\n                },\n                {\n                  field: \"family\",\n                  operator: Operators.Equals,\n                  value: \"test\",\n                  message: \"family should be test\",\n                },\n                {\n                  none: [\n                    {\n                      field: \"age\",\n                      operator: Operators.Equals,\n                      value: 19,\n                      message: \"age should be 19\",\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        { name: \"test2\", family: \"test2\", age: 18 },\n        true,\n      ),\n    ).toEqual(false);\n  });\n\n  it(\"should return false if field is undefined\", async () => {\n    expect(\n      await RuleEngine.getEvaluateResult(\n        {\n          conditions: [\n            {\n              and: [\n                {\n                  field: \"$.name\",\n                  operator: Operators.Equals,\n                  value: \"test\",\n                  message: \"name should be test\",\n                },\n              ],\n            },\n          ],\n        },\n        { family: \"test2\" },\n      ),\n    ).toEqual(false);\n  });\n\n  it(\"should return true for checkIsPassed method\", async () => {\n    const engine = RuleEngine.getInstance();\n    expect(\n      await engine.checkIsPassed(\n        {\n          conditions: [\n            {\n              and: [\n                {\n                  field: \"$.name\",\n                  operator: Operators.Equals,\n                  value: \"test\",\n                  message: \"name should be test\",\n                },\n              ],\n            },\n          ],\n        },\n        { name: \"test\" },\n      ),\n    ).toEqual(true);\n\n    expect(\n      await engine.checkIsPassed(\n        {\n          conditions: [\n            {\n              and: [\n                {\n                  field: \"$.name\",\n                  operator: Operators.Equals,\n                  value: \"test\",\n                  message: \"name should be test\",\n                },\n              ],\n            },\n          ],\n        },\n        [{ name: \"test\" }],\n      ),\n    ).toEqual(true);\n  });\n\n  it(\"should return true for evaluate multiple rules\", async () => {\n    const engine = RuleEngine.getInstance();\n    expect(\n      await engine.evaluateMany(\n        [\n          {\n            conditions: [\n              {\n                and: [\n                  {\n                    field: \"$.name\",\n                    operator: Operators.Equals,\n                    value: \"test\",\n                    message: \"name should be test\",\n                  },\n                ],\n              },\n            ],\n          },\n        ],\n        { name: \"test\" },\n      ),\n    ).toEqual([\n      {\n        isPassed: true,\n        value: true,\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "packages/core/test/introspector.spec.ts",
    "content": "import { it, expect, describe } from \"vitest\";\nimport { RuleTypeError, RuleEngine } from \"@root\";\n// Assets\nimport { valid2Json } from \"./rulesets/valid2.json\";\nimport { valid3Json } from \"./rulesets/valid3.json\";\nimport { valid4Json } from \"./rulesets/valid4.json\";\nimport { valid6Json } from \"./rulesets/valid6.json\";\nimport { valid7Json } from \"./rulesets/valid7.json\";\nimport { valid8Json } from \"./rulesets/valid8.json\";\nimport { valid9Json } from \"./rulesets/valid9.json\";\nimport { selfFieldsConstraintsJson } from \"./rulesets/self-fields-constraints.json\";\n\ndescribe(\"introspector correctly\", () => {\n  it(\"detects invalid rules\", async () => {\n    expect(() => RuleEngine.introspect(valid2Json)).toThrow(RuleTypeError);\n  });\n\n  it(\"introspects valid rules\", async () => {\n    expect(RuleEngine.introspect(selfFieldsConstraintsJson)).toEqual({\n      results: [\n        {\n          result: {\n            value: true,\n            message:\n              \"Password is valid and contains username($.username), name($.name) and family($.family)\",\n          },\n          options: [\n            {\n              \"$.meta.default.password\": [\n                {\n                  operator: \"self-not-contains-all\",\n                  value: [\"$.username\", \"$.name\", \"$.family\"],\n                },\n                {\n                  operator: \"not-like\",\n                  value: \"^A\",\n                },\n                {\n                  operator: \"like\",\n                  value: \"^@A%\",\n                },\n              ],\n            },\n          ],\n        },\n      ],\n      default: {\n        value: false,\n        message:\n          \"Password is invalid and contains username($.username), name($.name) and family($.family)\",\n      },\n    });\n\n    expect(RuleEngine.introspect(valid3Json)).toEqual({\n      results: [\n        {\n          result: {\n            value: 3,\n          },\n          options: [\n            {\n              Leverage: {\n                operator: \"greater-than-or-equals\",\n                value: 1000,\n              },\n            },\n            {\n              CountryIso: [\"GB\", \"FI\"],\n              Leverage: { operator: \"less-than\", value: 200 },\n              Monetization: \"Real\",\n            },\n          ],\n        },\n        { result: { value: 4 }, options: [{ Category: \"Islamic\" }] },\n      ],\n      default: { value: 2 },\n    });\n\n    expect(RuleEngine.introspect(valid4Json)).toEqual({\n      results: [\n        {\n          result: { value: 3 },\n          options: [\n            { Leverage: [1000, 500] },\n            {\n              CountryIso: { operator: \"contains\", value: [\"GB\", \"FI\"] },\n              Monetization: \"Real\",\n              Category: [\n                { operator: \"greater-than-or-equals\", value: 1000 },\n                22,\n                11,\n                12,\n              ],\n            },\n            {\n              CountryIso: { operator: \"contains\", value: [\"GB\", \"FI\"] },\n              Monetization: \"Real\",\n              Category: [\n                { operator: \"greater-than-or-equals\", value: 1000 },\n                22,\n              ],\n              HasStudentCard: true,\n              IsUnder18: true,\n            },\n          ],\n        },\n        { result: { value: 4 }, options: [{ Category: \"Islamic\" }] },\n      ],\n      default: { value: 2 },\n    });\n\n    expect(RuleEngine.introspect(valid6Json)).toEqual({\n      results: [\n        {\n          result: { value: 3 },\n          options: [\n            { Leverage: [1000, 500] },\n            {\n              CountryIso: { operator: \"contains\", value: [\"GB\", \"FI\"] },\n              Leverage: { operator: \"less-than\", value: 200 },\n              Monetization: \"Real\",\n              Category: [\n                { operator: \"greater-than-or-equals\", value: 1000 },\n                22,\n                11,\n                12,\n              ],\n            },\n            {\n              CountryIso: { operator: \"contains\", value: [\"GB\", \"FI\"] },\n              Leverage: { operator: \"less-than\", value: 200 },\n              Monetization: \"Real\",\n              Category: [\n                { operator: \"greater-than-or-equals\", value: 1000 },\n                22,\n                122,\n              ],\n              IsUnder18: true,\n            },\n          ],\n        },\n        { result: { value: 4 }, options: [{ Category: \"Islamic\" }] },\n      ],\n      default: { value: 2 },\n    });\n\n    expect(RuleEngine.introspect(valid7Json)).toEqual({\n      results: [\n        {\n          result: { value: 3 },\n          options: [\n            {\n              Leverage: [\n                { operator: \"less-than\", value: 1000 },\n                { operator: \"greater-than-or-equals\", value: 200 },\n              ],\n              CountryIso: { operator: \"not-in\", value: [\"GB\", \"FI\"] },\n              Monetization: { operator: \"not-equals\", value: \"Real\" },\n            },\n          ],\n        },\n        {\n          result: { value: 4 },\n          options: [{ Category: { operator: \"not-equals\", value: \"Islamic\" } }],\n        },\n      ],\n    });\n\n    expect(RuleEngine.introspect(valid8Json)).toEqual({\n      results: [\n        {\n          result: { value: 3 },\n          options: [\n            {\n              Leverage: { operator: \"less-than\", value: 1000 },\n              Type: \"Demo\",\n              OtherType: [\"Live\", \"Fun\"],\n            },\n            {\n              Leverage: [\n                { operator: \"less-than\", value: 1000 },\n                { operator: \"greater-than-or-equals\", value: 200 },\n              ],\n              CountryIso: { operator: \"not-in\", value: [\"GB\", \"FI\"] },\n              Monetization: { operator: \"not-equals\", value: \"Real\" },\n              OtherType: [],\n            },\n          ],\n        },\n        {\n          result: { value: 4 },\n          options: [{ Category: { operator: \"not-equals\", value: \"Islamic\" } }],\n        },\n      ],\n    });\n\n    expect(RuleEngine.introspect(valid9Json)).toEqual({\n      results: [\n        {\n          result: { value: 5 },\n          options: [\n            { country: \"SE\" },\n            {\n              country: [\"GB\", \"FI\"],\n              hasCoupon: true,\n              totalCheckoutPrice: {\n                operator: \"greater-than-or-equals\",\n                value: 120,\n              },\n            },\n          ],\n        },\n        {\n          result: { value: 10 },\n          options: [\n            {\n              age: { operator: \"greater-than-or-equals\", value: 18 },\n              hasStudentCard: true,\n            },\n          ],\n        },\n      ],\n    });\n  });\n});\n"
  },
  {
    "path": "packages/core/test/json-path.spec.ts",
    "content": "import { vi, it, expect, describe, beforeEach } from \"vitest\";\nimport { RuleEngine, ObjectDiscovery } from \"@root\";\n\nimport { selfFieldsConstraintsJson } from \"./rulesets/self-fields-constraints.json\";\n\ndescribe(\"json path correctly\", () => {\n  beforeEach(() => {\n    console.debug = vi.fn();\n    process.env.DEBUG = \"true\";\n  });\n\n  const discovery = new ObjectDiscovery();\n  it(\"resolves simple field definitions in a Text\", async () => {\n    expect(\n      discovery.resolveTextPathExpressions(\n        \"Password is invalid and contains username($.username), name($.name) and family($.family)\",\n        {\n          meta: {\n            default: {\n              password: \"@john-doe-@johndoe\",\n            },\n          },\n          username: \"john-doe\",\n          name: \"john\",\n          family: \"doe\",\n        },\n      ),\n    ).toEqual(\n      \"Password is invalid and contains username(john-doe), name(john) and family(doe)\",\n    );\n  });\n\n  it(\"resolves complex nested field definitions in a Text\", async () => {\n    const data = {\n      store: {\n        book: [\n          {\n            category: \"reference\",\n            author: \"Nigel Rees\",\n            title: \"Sayings of the Century\",\n            price: 8.95,\n          },\n          {\n            category: \"fiction\",\n            author: \"Evelyn Waugh\",\n            title: \"Sword of Honour\",\n            price: 12.99,\n          },\n          {\n            category: \"fiction\",\n            author: \"Herman Melville\",\n            title: \"Moby Dick\",\n            isbn: \"0-553-21311-3\",\n            price: 8.99,\n          },\n          {\n            category: \"fiction\",\n            author: \"J. R. R. Tolkien\",\n            title: \"The Lord of the Rings\",\n            isbn: \"0-395-19395-8\",\n            price: 22.99,\n          },\n        ],\n        bicycle: {\n          color: \"red\",\n          price: 19.95,\n        },\n      },\n    };\n\n    const expression = \"$.store.book[*].author\";\n    expect(\n      discovery.resolveTextPathExpressions(`Hi all ${expression}`, data),\n    ).toEqual(`Hi all ${discovery.resolveProperty(expression, data)}`);\n\n    const expressionB = \"$..author\";\n    expect(\n      discovery.resolveTextPathExpressions(`Hi all ${expressionB}`, data),\n    ).toEqual(`Hi all ${discovery.resolveProperty(expressionB, data)}`);\n  });\n\n  it(\"ruleEngine evaluate and return the resolved message correctly\", async () => {\n    expect(\n      await RuleEngine.evaluate(selfFieldsConstraintsJson, {\n        meta: {\n          default: {\n            password: \"@Aa101010@\",\n          },\n        },\n        username: \"john-doe\",\n        name: \"john\",\n        family: \"doe\",\n      }),\n    ).toEqual({\n      message:\n        \"Password is valid and contains username(john-doe), name(john) and family(doe)\",\n      value: true,\n      isPassed: true,\n    });\n  });\n});\n"
  },
  {
    "path": "packages/core/test/mutator.spec.ts",
    "content": "// Utilities\nimport axios from \"axios\";\nimport { RuleEngine, Operators } from \"@root\";\nimport { vi, it, expect, describe, beforeEach, afterEach } from \"vitest\";\n// Assets\nimport { valid1Json } from \"./rulesets/valid1.json\";\nimport { valid3Json } from \"./rulesets/valid3.json\";\n\n// Mock axios to avoid external HTTP requests in unit tests\nvi.mock(\"axios\");\nconst mockedAxios = vi.mocked(axios);\n\nconst mutation1 = async (value: unknown[]) => {\n  const result = await axios.get<{ cca2: any }>(\n    `https://restcountries.com/v3.1/name/${value}?fullText=true`,\n  );\n  // @ts-ignore\n  return result.data?.[0].cca2;\n};\n\nconst mutation2 = async (value: unknown[]) => {\n  const result = await axios.get<{ cca2: any }>(\n    `https://restcountries.com/v3.1/name/${value[0]}?fullText=true`,\n  );\n  // @ts-ignore\n  return result.data[0].cca2;\n};\n\nconst criteria = [\n  {\n    CountryIso: \"United Kingdom\",\n    Leverage: 60,\n    Monetization: \"Real\",\n  },\n  {\n    CountryIso: \"United Kingdom\",\n    Leverage: 200,\n    Monetization: \"Real\",\n  },\n  {\n    CountryIso: \"United Kingdom\",\n    Leverage: 60,\n    Monetization: \"Real\",\n  },\n];\n\ndescribe(\"mutator correctly\", () => {\n  beforeEach(() => {\n    console.debug = vi.fn();\n    process.env.DEBUG = \"true\";\n\n    // Setup axios mock responses\n    (mockedAxios.get as any).mockImplementation((url: string) => {\n      if (url.includes(\"United Kingdom\")) {\n        return Promise.resolve({\n          data: [{ cca2: \"GB\" }],\n        });\n      }\n      if (url.includes(\"Spain\")) {\n        return Promise.resolve({\n          data: [{ cca2: \"ES\" }],\n        });\n      }\n      // Default response for any other country\n      return Promise.resolve({\n        data: [{ cca2: \"US\" }],\n      });\n    });\n  });\n\n  afterEach(() => {\n    // Clear mutations and cache after each test to ensure test isolation\n    const rp = RuleEngine.getInstance();\n    rp.clearMutations();\n    rp.clearMutationCache();\n    rp.clearCache();\n\n    // Clear axios mocks\n    vi.clearAllMocks();\n  });\n\n  it(\"performs desired mutation\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    rp.addMutation(\"$.payload.ProfitPercentage\", (value: number) => value * 2);\n    expect(\n      await rp.getEvaluateResult(valid1Json, {\n        payload: { ProfitPercentage: 5 },\n      }),\n    ).toEqual(true);\n  });\n\n  it(\"performs multiple mutations\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    rp.addMutation(\"WinRate\", (value: number) => value * 2);\n    rp.addMutation(\"AverageTradeDuration\", (value: number) => value / 2);\n\n    expect(\n      await rp.getEvaluateResult(valid1Json, {\n        WinRate: 31,\n        AverageTradeDuration: 60,\n        Duration: 99999999,\n        TotalDaysTraded: 3,\n      }),\n    ).toEqual(true);\n  });\n\n  it(\"performs async mutation\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    rp.addMutation(\"CountryIso\", mutation1);\n\n    expect(\n      await rp.getEvaluateResult(valid3Json, {\n        CountryIso: \"United Kingdom\",\n        Leverage: 60,\n        Monetization: \"Real\",\n        foo: {\n          CountryIso: \"United Kingdom\",\n        },\n      }),\n    ).toEqual(3);\n  });\n\n  it(\"performs nested mutation\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    rp.addMutation(\"$.foo.bar\", (value: number) => value * 2);\n    expect(\n      await rp.getEvaluateResult(\n        {\n          conditions: [\n            {\n              and: [\n                {\n                  field: \"$.foo.bar\",\n                  operator: Operators.GreaterThan,\n                  value: 6,\n                },\n              ],\n            },\n          ],\n        },\n        { foo: { bar: 5 } },\n      ),\n    ).toEqual(true);\n  });\n\n  it(\"caches async mutation results\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    rp.addMutation(\"Leverage\", (value: unknown) => value);\n    rp.addMutation(\"CountryIso\", mutation1);\n\n    const result = await rp.getEvaluateResult(valid3Json, criteria);\n\n    expect(console.debug).toBeCalledWith(\n      'Waiting on mutation \"CountryIso\" with param \"United Kingdom\"',\n    );\n    expect(console.debug).toBeCalledTimes(9);\n    expect(result).toEqual([3, 2, 3]);\n  });\n\n  it(\"performs a migration with an array parameter\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    rp.addMutation(\"CountryIso\", mutation2);\n\n    const result = await rp.getEvaluateResult(\n      {\n        conditions: [\n          {\n            and: [\n              { field: \"CountryIso\", operator: Operators.Equals, value: \"GB\" },\n            ],\n          },\n        ],\n      },\n      { CountryIso: [\"United Kingdom\", \"Finland\"] },\n    );\n\n    expect(result).toEqual(true);\n  });\n\n  it(\"performs a migration with a nested array parameter\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    rp.addMutation(\"$.foo.bar\", mutation2);\n\n    const result = await rp.getEvaluateResult(\n      {\n        conditions: [\n          {\n            and: [\n              { field: \"$.foo.bar\", operator: Operators.Equals, value: \"GB\" },\n            ],\n          },\n        ],\n      },\n      { foo: { bar: [\"United Kingdom\", \"Finland\"] } },\n    );\n\n    expect(result).toEqual(true);\n  });\n\n  it(\"mutation cache works properly\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    rp.addMutation(\"Leverage\", (value: unknown) => value);\n    rp.addMutation(\"CountryIso\", mutation1);\n\n    await rp.getEvaluateResult(valid3Json, criteria);\n\n    setTimeout(async () => {\n      const result = await rp.getEvaluateResult(valid3Json, criteria);\n      expect(console.debug).toBeCalledWith(\n        'Cache hit on \"CountryIso\" with param \"United Kingdom\"',\n      );\n      expect(result).toEqual([3, 2, 3]);\n    }, 1500);\n  });\n\n  it(\"removes a mutation properly\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    rp.addMutation(\"CountryIso\", mutation1);\n    rp.removeMutation(\"CountryIso\");\n\n    const result = await rp.getEvaluateResult(valid3Json, {\n      CountryIso: \"United Kingdom\",\n      Leverage: 60,\n      Monetization: \"Real\",\n    });\n\n    expect(console.debug).not.toHaveBeenCalled();\n    expect(result).toEqual(2);\n  });\n\n  it(\"clears mutation cache properly\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    rp.addMutation(\"CountryIso\", mutation1);\n\n    await rp.evaluate(valid3Json, {\n      CountryIso: \"United Kingdom\",\n      Leverage: 60,\n      Monetization: \"Real\",\n    });\n\n    rp.clearMutationCache(\"CountryIso\");\n\n    const result = await rp.getEvaluateResult(valid3Json, {\n      CountryIso: \"United Kingdom\",\n      Leverage: 60,\n      Monetization: \"Real\",\n    });\n\n    expect(console.debug).not.toHaveBeenCalledWith(\n      'Waiting on mutation \"CountryIso\" with param \"United Kingdom\"',\n    );\n    expect(result).toEqual(3);\n  });\n\n  it(\"clears all mutation cache properly\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    rp.addMutation(\"CountryIso\", mutation1);\n\n    await rp.evaluate(valid3Json, {\n      CountryIso: \"United Kingdom\",\n      Leverage: 60,\n      Monetization: \"Real\",\n    });\n\n    rp.clearMutationCache();\n\n    const result = await rp.getEvaluateResult(valid3Json, {\n      CountryIso: \"United Kingdom\",\n      Leverage: 60,\n      Monetization: \"Real\",\n    });\n\n    expect(console.debug).not.toHaveBeenCalledWith(\n      'Waiting on mutation \"CountryIso\" with param \"United Kingdom\"',\n    );\n    expect(result).toEqual(3);\n  });\n\n  it(\"static methods behave as expected\", async () => {\n    const rp = RuleEngine.getInstance();\n\n    RuleEngine.addMutation(\"CountryIso\", mutation1);\n\n    const result1 = await RuleEngine.getEvaluateResult(valid3Json, {\n      CountryIso: \"United Kingdom\",\n      Leverage: 60,\n      Monetization: \"Real\",\n    });\n\n    expect(result1).toEqual(3);\n\n    RuleEngine.removeMutation(\"CountryIso\");\n    const result2 = await rp.getEvaluateResult(valid3Json, {\n      CountryIso: \"United Kingdom\",\n      Leverage: 60,\n      Monetization: \"Real\",\n    });\n\n    expect(result2).toEqual(2);\n\n    RuleEngine.clearMutationCache();\n    const result3 = await rp.getEvaluateResult(valid3Json, {\n      CountryIso: \"United Kingdom\",\n      Leverage: 60,\n      Monetization: \"Real\",\n    });\n\n    expect(console.debug).not.toHaveBeenCalledWith(\n      'Waiting on mutation \"CountryIso\" with param \"United Kingdom\"',\n    );\n    expect(result3).toEqual(2);\n  });\n});\n"
  },
  {
    "path": "packages/core/test/operators.spec.ts",
    "content": "import { it, expect, describe } from \"vitest\";\n\nimport {\n  selfContainsAnyOperator,\n  selfContainsAllOperator,\n  RuleEngine,\n  Operators,\n  matchesOperator,\n  likeOperator,\n  lessThanOrEqualsOperator,\n  lessThanOperator,\n  isZeroOperator,\n  isUuidOperator,\n  isUrlOperator,\n  isUpperCaseOperator,\n  isTruthyOperator,\n  isTimeEqualsOperator,\n  isTimeBetweenOperator,\n  isTimeBeforeOrEqualsOperator,\n  isTimeBeforeOperator,\n  isTimeAfterOrEqualsOperator,\n  isTimeAfterOperator,\n  isStringOperator,\n  isPositiveOperator,\n  isPersianAlphaOperator,\n  isPersianAlphaNumericOperator,\n  isObjectOperator,\n  isNumericOperator,\n  isNumberOperator,\n  isNumberBetweenOperator,\n  isNullOrWhiteSpaceOperator,\n  isNullOrUndefinedOperator,\n  isNegativeOperator,\n  isMinOperator,\n  isMinLengthOperator,\n  isMaxOperator,\n  isMaxLengthOperator,\n  isLowerCaseOperator,\n  isLengthOperator,\n  IsLengthBetweenOperator,\n  isIntegerOperator,\n  isFloatOperator,\n  isFalsyOperator,\n  isExistsInObjectOperator,\n  isEmptyOperator,\n  isEmailOperator,\n  isDateOperator,\n  isDateEqualsOperator,\n  isDateBetweenOperator,\n  isDateBeforeOrEqualsOperator,\n  isDateBeforeOperator,\n  isDateAfterOrEqualsOperator,\n  isDateAfterOperator,\n  isBooleanStringOperator,\n  isBooleanOperator,\n  isBooleanNumberStringOperator,\n  isBooleanNumberOperator,\n  isBetweenOperator,\n  isArrayOperator,\n  isAlphaOperator,\n  isAlphaNumericOperator,\n  inOperator,\n  greaterThanOrEqualsOperator,\n  greaterThanOperator,\n  equalsOperator,\n  containsOperator,\n  containsAnyOperator,\n  containsAllOperator,\n} from \"@root\";\n\ndescribe(\"rule Engine Evaluation Operators\", () => {\n  ///////////////////////////\n  // :: LIKE OPERATOR :: //\n  ///////////////////////////\n  describe(\"likeOperator\", () => {\n    describe(\"likeOperator function\", () => {\n      it(\"should match a simple pattern with wildcards\", () => {\n        const text = \"This is a simple string\";\n        const pattern = \"%simple%\";\n        expect(likeOperator(text, pattern)).toBeTruthy();\n      });\n      it(\"should match a simple pattern with wildcards 2\", () => {\n        const text = \"@Aa101010\";\n        const pattern = \"^@A%\";\n        expect(likeOperator(text, pattern)).toBeTruthy();\n      });\n      it(\"should match a pattern with a wildcard at the beginning\", () => {\n        const text = \"This is a simple string\";\n        const pattern = \"%This%\";\n        expect(likeOperator(text, pattern)).toBeTruthy();\n      });\n\n      it(\"should match a pattern with a wildcard at the end\", () => {\n        const text = \"This is a simple string\";\n        const pattern = \"%string\";\n        expect(likeOperator(text, pattern)).toBeTruthy();\n      });\n\n      it(\"should match a pattern with a wildcard at the beginning and end\", () => {\n        const text = \"This is a simple string\";\n        const pattern = \"%is a simple%\";\n        expect(likeOperator(text, pattern)).toBeTruthy();\n      });\n\n      /**\n       * text = \"abc_x_defg\" => pattern = \"abc_de_%\" => true\n       * text = \"abc_y_123\" => pattern = \"abc_de_%\" => false\n       * text = \"abc_def\" => pattern = \"abc_de_%\" => true\n       * text = \"abc_defg\" => pattern = \"abc_de_%\" => true\n       * text = \"abc_de_defg\" => pattern = \"abc_de_%g\" => true\n       * text = \"abc_y_123\" => pattern = \"abc_de_%g\" => false\n       */\n      it(\"should match a pattern with an underscore character set\", () => {\n        const text = \"abc_x_defg\";\n        const pattern = \"abc_de_%\";\n        expect(likeOperator(text, pattern)).toBeFalsy();\n\n        const text2 = \"abc_y_123\";\n        const pattern2 = \"abc_de_%\";\n        expect(likeOperator(text2, pattern2)).toBeFalsy();\n\n        const text3 = \"abc_def\";\n        const pattern3 = \"abc_de_%\";\n        expect(likeOperator(text3, pattern3)).toBeTruthy();\n\n        const text4 = \"abc_defg\";\n        const pattern4 = \"abc_de_%\";\n        expect(likeOperator(text4, pattern4)).toBeTruthy();\n\n        const text5 = \"abc_x_defg\";\n        const pattern5 = \"abc_de_%g\";\n        expect(likeOperator(text5, pattern5)).toBeFalsy();\n\n        const text6 = \"abc_y_123\";\n        const pattern6 = \"abc_de_%g\";\n        expect(likeOperator(text6, pattern6)).toBeFalsy();\n      });\n\n      /**\n       * text = \"a_def\" => pattern = \"[a-c]_%\" => true\n       * text = \"b_ghi\" => pattern = \"[a-c]_%\" => true\n       * text = \"c_jkl\" => pattern = \"[a-c]_%\" => true\n       * text = \"d_mno\" => pattern = \"[a-c]_%\" => false\n       */\n      it(\"should match a pattern with a character set\", () => {\n        const text = \"a_def\";\n        const pattern = \"[a-c]_%\";\n        expect(likeOperator(text, pattern)).toBeTruthy();\n\n        const text2 = \"b_ghi\";\n        const pattern2 = \"[a-c]_%\";\n        expect(likeOperator(text2, pattern2)).toBeTruthy();\n\n        const text3 = \"c_jkl\";\n        const pattern3 = \"[a-c]_%\";\n        expect(likeOperator(text3, pattern3)).toBeTruthy();\n\n        const text4 = \"d_mno\";\n        const pattern4 = \"[a-c]_%\";\n        expect(likeOperator(text4, pattern4)).toBeFalsy();\n      });\n\n      /**\n       * text = \"x_def\" => pattern = \"[^aeiou]_%\" => true\n       * text = \"z_ghi\" => pattern = \"[^aeiou]_%\" => true\n       * text = \"a_jkl\" => pattern = \"[^aeiou]_%\" => false\n       * text = \"e_mno\" => pattern = \"[^aeiou]_%\" => false\n       */\n      it(\"should match a pattern with a character set range\", () => {\n        const text = \"x_def\";\n        const pattern = \"[^aeiou]_%\";\n        expect(likeOperator(text, pattern)).toBeTruthy();\n\n        const text2 = \"z_ghi\";\n        const pattern2 = \"[^aeiou]_%\";\n        expect(likeOperator(text2, pattern2)).toBeTruthy();\n\n        const text3 = \"a_jkl\";\n        const pattern3 = \"[^aeiou]_%\";\n        expect(likeOperator(text3, pattern3)).toBeFalsy();\n\n        const text4 = \"e_mno\";\n        const pattern4 = \"[^aeiou]_%\";\n        expect(likeOperator(text4, pattern4)).toBeFalsy();\n      });\n\n      /**\n       * text = \"This is an example string\" => pattern = \"The\\%is is an exa\\%ple str%ng\" => true\n       * text = \"This is an example string\" => pattern = \"The\\%is is an exa%ple str%ng\" => true\n       * text = \"This is an example string\" => pattern = \"The\\%is is an exa\\%ple str%ng\" => true\n       */\n      it(\"should handle escaped special characters\", () => {\n        const text = \"This is an example string\";\n        const pattern = \"Th%is is an exa%ple str%ng\";\n        expect(likeOperator(text, pattern)).toBeTruthy();\n\n        const text2 = \"This is an example string\";\n        const pattern2 = \"Th%is is an exa%ple str%ng\";\n        expect(likeOperator(text2, pattern2)).toBeTruthy();\n\n        const text3 = \"This is an example string\";\n        const pattern3 = \"Th%is is an exa%ple str%ng\";\n        expect(likeOperator(text3, pattern3)).toBeTruthy();\n      });\n\n      /**\n       * text = \"myfile.txt\" => pattern = \"%.txt\" => true\n       * text = \"document.txt\" => pattern = \"%.txt\" => true\n       * text = \"image.jpg\" => pattern = \"%.txt\" => false\n       * text = \"myfile.txt\" => pattern = \"myfile.%\" => true\n       * text = \"myfile.txt\" => pattern = \"myfile.txt%\" => true\n       * text = \"myfile.txt\" => pattern = \"myfile.txt\" => true\n       */\n      it(\"should match a pattern with a wildcard character\", () => {\n        const text = \"myfile.txt\";\n        const pattern = \"%.txt\";\n        expect(likeOperator(text, pattern)).toBeTruthy();\n\n        const text2 = \"document.txt\";\n        const pattern2 = \"%.txt\";\n        expect(likeOperator(text2, pattern2)).toBeTruthy();\n\n        const text3 = \"image.jpg\";\n        const pattern3 = \"%.txt\";\n        expect(likeOperator(text3, pattern3)).toBeFalsy();\n\n        const text4 = \"myfile.txt\";\n        const pattern4 = \"myfile.%\";\n        expect(likeOperator(text4, pattern4)).toBeTruthy();\n\n        const text5 = \"myfile.txt\";\n        const pattern5 = \"myfile.txt%\";\n        expect(likeOperator(text5, pattern5)).toBeTruthy();\n\n        const text6 = \"myfile.txt\";\n        const pattern6 = \"myfile.txt\";\n        expect(likeOperator(text6, pattern6)).toBeTruthy();\n      });\n\n      it(\"should not match if the pattern is not present\", () => {\n        const text = \"This is a different string\";\n        const pattern = \"%manager%\";\n        expect(likeOperator(text, pattern)).toBeFalsy();\n      });\n\n      it(\"should handle empty pattern\", () => {\n        const text = \"Any string\";\n        const pattern = \"\";\n        expect(likeOperator(text, pattern)).toBeFalsy();\n      });\n\n      it(\"should handle empty text\", () => {\n        const text = \"\";\n        const pattern = \"%any%\";\n        expect(likeOperator(text, pattern)).toBeFalsy();\n      });\n\n      it(\"should not match if the underscore is not part of the pattern\", () => {\n        const text = \"helloworld\";\n        const pattern = \"hello_\";\n        expect(likeOperator(text, pattern)).toBeFalsy();\n      });\n\n      it(\"should handle escaped special characters outside character sets\", () => {\n        const text = \"special_chars\";\n        const pattern = \"\\\\$\\\\&\";\n        expect(likeOperator(text, pattern)).toBeFalsy();\n      });\n\n      it(\"should handle * wildcard\", () => {\n        const text = \"This is a simple string\";\n        const pattern = \"simple*\";\n        expect(likeOperator(text, pattern)).toBeFalsy();\n\n        const text2 = \"This is a simple string\";\n        const pattern2 = \"*simple*\";\n        expect(likeOperator(text2, pattern2)).toBeFalsy();\n\n        const text3 = \"This is a simple string\";\n        const pattern3 = \"*simple\";\n        expect(likeOperator(text3, pattern3)).toBeFalsy();\n\n        const text4 = \"This is a simple string\";\n        const pattern4 = \"sim*ple\";\n        expect(likeOperator(text4, pattern4)).toBeFalsy();\n      });\n\n      it(\"should handle ? ! ^ $ wildcards\", () => {\n        const text = \"This is a simple string\";\n        const pattern = \"simple?\";\n        expect(likeOperator(text, pattern)).toBeFalsy();\n\n        const text2 = \"This is a simple string\";\n        const pattern2 = \"!simple!\";\n        expect(likeOperator(text2, pattern2)).toBeFalsy();\n\n        const text3 = \"This is a simple string\";\n        const pattern3 = \"^simple\";\n        expect(likeOperator(text3, pattern3)).toBeFalsy();\n\n        const text4 = \"This is a simple string\";\n        const pattern4 = \"simple^\";\n        expect(likeOperator(text4, pattern4)).toBeFalsy();\n\n        const text5 = \"This is a simple string\";\n        const pattern5 = \"simple$\";\n        expect(likeOperator(text5, pattern5)).toBeFalsy();\n      });\n    });\n\n    describe(\"like Operator\", () => {\n      it(\"should match a simple pattern with wildcards\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"text\", operator: Operators.Like, value: \"%simple%\" },\n            ],\n          },\n        ];\n        const data = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { text: \"This is a complex string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeFalsy();\n\n        const data3 = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n      });\n\n      it(\"should match a pattern with a wildcard at the beginning\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"text\", operator: Operators.Like, value: \"%This%\" }],\n          },\n        ];\n        const data = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { text: \"is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeFalsy();\n\n        const data3 = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n      });\n\n      it(\"should match a pattern with a wildcard at the end\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"text\", operator: Operators.Like, value: \"%string\" },\n            ],\n          },\n        ];\n        const data = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { text: \"This is a simple\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeFalsy();\n\n        const data3 = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n      });\n\n      it(\"should match a pattern with a wildcard at the beginning and end\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"text\",\n                operator: Operators.Like,\n                value: \"%is a simple%\",\n              },\n            ],\n          },\n        ];\n        const data = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { text: \"This is a string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeFalsy();\n\n        const data3 = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n      });\n\n      it(\"should match a pattern with an underscore character set\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"text\", operator: Operators.Like, value: \"abc_de_%\" },\n            ],\n          },\n        ];\n        const data = { text: \"abc_x_defg\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n\n        const data2 = { text: \"abc_y_123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeFalsy();\n\n        const data3 = { text: \"abc_def\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n\n        const data4 = { text: \"abc_defg\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeTruthy();\n\n        const data5 = { text: \"abc_x_defg\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data5),\n        ).toBeFalsy();\n\n        const data6 = { text: \"abc_y_123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data6),\n        ).toBeFalsy();\n      });\n\n      it(\"should match a pattern with a character set\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"text\", operator: Operators.Like, value: \"[a-c]_%\" },\n            ],\n          },\n        ];\n        const data = { text: \"a_def\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { text: \"b_ghi\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n\n        const data3 = { text: \"c_jkl\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n\n        const data4 = { text: \"d_mno\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeFalsy();\n      });\n\n      it(\"should match a pattern with a character set range\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"text\", operator: Operators.Like, value: \"[^aeiou]_%\" },\n            ],\n          },\n        ];\n        const data = { text: \"x_def\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { text: \"z_ghi\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n\n        const data3 = { text: \"a_jkl\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeFalsy();\n\n        const data4 = { text: \"e_mno\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeFalsy();\n      });\n\n      it(\"should handle escaped special characters\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"text\",\n                operator: Operators.Like,\n                value: \"Th%is is an exa%ple str%ng\",\n              },\n            ],\n          },\n        ];\n        const data = { text: \"This is an example string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { text: \"This is an example string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n\n        const data3 = { text: \"This is an example string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n      });\n\n      it(\"should match a pattern with a wildcard character\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"text\", operator: Operators.Like, value: \"%.txt\" }],\n          },\n        ];\n        const data = { text: \"myfile.txt\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { text: \"document.txt\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n\n        const data3 = { text: \"image.jpg\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeFalsy();\n\n        const data4 = { text: \"myfile.txt\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeTruthy();\n\n        const data5 = { text: \"myfile.txt\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data5),\n        ).toBeTruthy();\n\n        const data6 = { text: \"myfile.txt\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data6),\n        ).toBeTruthy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: REGEXP OPERATOR :: //\n  ///////////////////////////\n  describe(\"matches Operator\", () => {\n    it(\"should match a simple pattern\", () => {\n      const text = \"This is a simple string\";\n      const pattern = \"simple\";\n      expect(matchesOperator(text, pattern)).toBeTruthy();\n    });\n    it(\"should match a pattern with a wildcard\", () => {\n      const text = \"This is a simple string\";\n      const pattern = \"simple.*\";\n      expect(matchesOperator(text, pattern)).toBeTruthy();\n    });\n    it(\"should match a pattern with a character set\", () => {\n      const text = \"This is a simple string\";\n      const pattern = \"simple [a-z]\";\n      expect(matchesOperator(text, pattern)).toBeTruthy();\n    });\n\n    it(\"should match a pattern with a character set range\", () => {\n      const text = \"This is a simple string\";\n      const pattern = \"simple [a-z]\";\n      expect(matchesOperator(text, pattern)).toBeTruthy();\n    });\n\n    it(\"should match a pattern with at least one uppercase char\", () => {\n      const text = \"This is a simple string\";\n      const pattern = \"^(?=.*?[A-Z]).*$\";\n      expect(matchesOperator(text, pattern)).toBeTruthy();\n    });\n\n    it(\"should match a pattern with at least one lowercase char\", () => {\n      const text = \"This is a simple string\";\n      const pattern = \"^(?=.*?[a-z]).*$\";\n      expect(matchesOperator(text, pattern)).toBeTruthy();\n    });\n\n    it(\"should match a pattern with at least one digit\", () => {\n      const text = \"This is 1 simple string\";\n      const pattern = \"^(?=.*?[0-9]).*$\";\n      expect(matchesOperator(text, pattern)).toBeTruthy();\n    });\n\n    it(\"should match a pattern with at least one special char\", () => {\n      const text = \"This is a simple string\";\n      const pattern = \"^(?=.*?[#?!@$%^&*-]).*$\";\n      expect(matchesOperator(text, pattern)).toBeFalsy();\n    });\n\n    it(\"should handle escaped special characters\", () => {\n      const text = \"This is an example string\";\n      const pattern = \"Th%is is an exa%ple str%ng\";\n      expect(matchesOperator(text, pattern)).toBeFalsy();\n    });\n\n    it(\"should match a pattern with a wildcard character\", () => {\n      const text = \"myfile.txt\";\n      const pattern = \".txt$\";\n      expect(matchesOperator(text, pattern)).toBeTruthy();\n    });\n\n    it(\"should not match if the pattern is not present\", () => {\n      const text = \"This is a different string\";\n      const pattern = \"manager\";\n      expect(matchesOperator(text, pattern)).toBeFalsy();\n    });\n\n    it(\"should handle empty pattern\", () => {\n      const text = \"Any string\";\n      const pattern = \"\";\n      expect(matchesOperator(text, pattern)).toBeFalsy();\n    });\n\n    it(\"should handle empty text\", () => {\n      const text = \"\";\n      const pattern = \"any\";\n      expect(matchesOperator(text, pattern)).toBeFalsy();\n    });\n\n    it(\"should not match if the underscore is not part of the pattern\", () => {\n      const text = \"helloworld\";\n      const pattern = \"hello_\";\n      expect(matchesOperator(text, pattern)).toBeFalsy();\n    });\n\n    // check Email regex\n    it(\"should match a valid email\", () => {\n      const text = \"test@gmail.com\";\n      const pattern = \"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$\";\n      expect(matchesOperator(text, pattern)).toBeTruthy();\n    });\n\n    describe(\"matches Operator\", () => {\n      it(\"should match a simple pattern\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"text\", operator: Operators.Matches, value: \"simple\" },\n            ],\n          },\n        ];\n        const data = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should match a pattern with a wildcard\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"text\", operator: Operators.Matches, value: \"simple.*\" },\n            ],\n          },\n        ];\n        const data = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should match a pattern with a character set\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"text\",\n                operator: Operators.Matches,\n                value: \"simple [a-z]\",\n              },\n            ],\n          },\n        ];\n        const data = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should match a pattern with a character set range\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"text\",\n                operator: Operators.Matches,\n                value: \"simple [a-z]\",\n              },\n            ],\n          },\n        ];\n        const data = { text: \"This is a simple string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should not match if the pattern is not present\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"text\", operator: Operators.Matches, value: \"manager\" },\n            ],\n          },\n        ];\n        const data = { text: \"This is a different string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should handle empty pattern\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"text\", operator: Operators.Matches, value: \"\" }],\n          },\n        ];\n        const data = { text: \"Any string\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should handle empty text\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"text\", operator: Operators.Matches, value: \"any\" }],\n          },\n        ];\n        const data = { text: \"\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should not match if the underscore is not part of the pattern\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"text\", operator: Operators.Matches, value: \"hello_\" },\n            ],\n          },\n        ];\n        const data = { text: \"helloworld\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n      // check Email regex\n      it(\"should match a valid email\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"email\",\n                operator: Operators.Matches,\n                value: \"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$\",\n              },\n            ],\n          },\n        ];\n        const data = { email: \"test@gmail.com\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { email: \"test@gmail\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeFalsy();\n\n        const data3 = { email: \"testgmail.com\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeFalsy();\n\n        const data4 = { email: \"test@gmail.\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeFalsy();\n      });\n\n      // check URL regex\n      it(\"should match a valid URL\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"url\",\n                operator: Operators.Matches,\n                value:\n                  \"/(https?:\\\\/\\\\/(?:www\\\\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\\\.[^\\\\s]{2,}|www\\\\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\\\.[^\\\\s]{2,}|https?:\\\\/\\\\/(?:www\\\\.|(?!www))[a-zA-Z0-9]+\\\\.[^\\\\s]{2,}|www\\\\.[a-zA-Z0-9]+\\\\.[^\\\\s]{2,})/\",\n              },\n            ],\n          },\n        ];\n        const data = { url: \"https://www.google.com\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { url: \"http://www.google.com\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n\n        const data3 = { url: \"http://www.google\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeFalsy();\n\n        const data4 = { url: \"https://www.google.\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS NULL OR WHITE SPACE OPERATOR :: //\n  ///////////////////////////\n  describe(\"isNullOrWhiteSpaceOperator\", () => {\n    it(\"should return true for null\", () => {\n      const text = null;\n      expect(\n        isNullOrWhiteSpaceOperator(text as unknown as string),\n      ).toBeTruthy();\n    });\n\n    it(\"should return true for undefined\", () => {\n      const text = undefined;\n      expect(\n        isNullOrWhiteSpaceOperator(text as unknown as string),\n      ).toBeTruthy();\n    });\n\n    it(\"should return true for empty string\", () => {\n      const text = \"\";\n      expect(isNullOrWhiteSpaceOperator(text)).toBeTruthy();\n    });\n\n    it(\"should return true for white space\", () => {\n      const text = \" \";\n      expect(isNullOrWhiteSpaceOperator(text)).toBeTruthy();\n    });\n\n    it(\"should return false for a string with content\", () => {\n      const text = \"Some text\";\n      expect(isNullOrWhiteSpaceOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isNullOrWhiteSpace Operator\", () => {\n      it(\"should return true for null\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"text\", operator: Operators.NullOrWhiteSpace }],\n          },\n        ];\n        const data = { text: null };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { text: undefined };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n\n        const data3 = { text: \"\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n\n        const data4 = { text: \" \" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string with content\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"text\", operator: Operators.NullOrWhiteSpace }],\n          },\n        ];\n        const data = { text: \"Some text\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS NUMERIC OPERATOR :: //\n  ///////////////////////////\n  describe(\"isNumericOperator\", () => {\n    it(\"should return true for a number\", () => {\n      const text = \"123\";\n      expect(isNumericOperator(text)).toBeTruthy();\n    });\n    it(\"should return true for a negative number\", () => {\n      const text = \"-123\";\n      expect(isNumericOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isNumericOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string with numbers\", () => {\n      const text = \"abc123\";\n      expect(isNumericOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string with numbers and special characters\", () => {\n      const text = \"abc123$\";\n      expect(isNumericOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isNumeric Operator\", () => {\n      it(\"should return true for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"number\", operator: Operators.Numeric }],\n          },\n        ];\n        const data = { number: \"123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { number: \"-123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"number\", operator: Operators.Numeric }],\n          },\n        ];\n        const data = { number: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string with numbers\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"number\", operator: Operators.Numeric }],\n          },\n        ];\n        const data = { number: \"abc123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string with numbers and special characters\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"number\", operator: Operators.Numeric }],\n          },\n        ];\n        const data = { number: \"abc123$\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS BOOLEAN OPERATOR :: //\n  ///////////////////////////\n  describe(\"isBooleanOperator\", () => {\n    it(\"should return true for true\", () => {\n      const inp = true;\n      expect(isBooleanOperator(inp)).toBeTruthy();\n    });\n    it(\"should return true for false\", () => {\n      const inp = false;\n      expect(isBooleanOperator(inp)).toBeTruthy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = \"123\";\n      expect(isBooleanOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isBooleanOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string contains false as string\", () => {\n      const text = \"true\";\n      expect(isBooleanOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string contains true as string\", () => {\n      const text = \"false\";\n      expect(isBooleanOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isBoolean Operator\", () => {\n      it(\"should return true for true\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"bool\", operator: Operators.Boolean }],\n          },\n        ];\n        const data = { bool: true };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { bool: false };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"bool\", operator: Operators.Boolean }],\n          },\n        ];\n        const data = { bool: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"bool\", operator: Operators.Boolean }],\n          },\n        ];\n        const data = { bool: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string contains false as string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"bool\", operator: Operators.Boolean }],\n          },\n        ];\n        const data = { bool: \"true\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS DATE OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isDateOperator\", () => {\n    it(\"should return true for a date string\", () => {\n      const text = \"2020-01-01\";\n      expect(isDateOperator(text)).toBeTruthy();\n    });\n    it(\"should return true for a date string with time\", () => {\n      const text = \"2020-01-01T00:00:00\";\n      expect(isDateOperator(text)).toBeTruthy();\n    });\n    it(\"should return true for a number(God damn it)\", () => {\n      const text = \"123\";\n      expect(isDateOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isDateOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string contains date as string\", () => {\n      const text = \"date\";\n      expect(isDateOperator(text)).toBeFalsy();\n\n      const text2 = \"time\";\n      expect(isDateOperator(text2)).toBeFalsy();\n    });\n\n    describe(\"isDate Operator\", () => {\n      it(\"should return true for a date string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"date\", operator: Operators.Date }],\n          },\n        ];\n        const data = { date: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { date: \"2020-01-01T00:00:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n\n        const data3 = { date: \"123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"date\", operator: Operators.Date }],\n          },\n        ];\n        const data4 = { date: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeFalsy();\n\n        const data5 = { date: \"date\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data5),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS EMAIL OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isEmailOperator\", () => {\n    it(\"should return true for a valid email\", () => {\n      const text = \"test@gmail.com\";\n      expect(isEmailOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = \"123\";\n      expect(isEmailOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isEmailOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string contains email as string\", () => {\n      const text = \"email\";\n      expect(isEmailOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isEmail Operator\", () => {\n      it(\"should return true for a valid email\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"email\", operator: Operators.Email }],\n          },\n        ];\n        const data = { email: \"test@gmail.com\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"email\", operator: Operators.Email }],\n          },\n        ];\n        const data = { email: \"123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS URL OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isUrlOperator\", () => {\n    it(\"should return true for a valid url\", () => {\n      const text = \"https://www.google.com\";\n      expect(isUrlOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = \"123\";\n      expect(isUrlOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isUrlOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string contains url as string\", () => {\n      const text = \"url\";\n      expect(isUrlOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isUrl Operator\", () => {\n      it(\"should return true for a valid url\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"url\", operator: Operators.Url }],\n          },\n        ];\n        const data = { url: \"https://www.google.com\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"url\", operator: Operators.Url }],\n          },\n        ];\n        const data = { url: \"123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"url\", operator: Operators.Url }],\n          },\n        ];\n        const data = { url: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS UUID OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isUuidOperator\", () => {\n    it(\"should return true for a valid UUID\", () => {\n      const text = \"550e8400-e29b-41d4-a716-446655440000\";\n      expect(isUuidOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = \"123\";\n      expect(isUuidOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isUuidOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string contains UUID as string\", () => {\n      const text = \"uuid\";\n      expect(isUuidOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isUuid Operator\", () => {\n      it(\"should return true for a valid UUID\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"uuid\", operator: Operators.UUID }],\n          },\n        ];\n        const data = { uuid: \"550e8400-e29b-41d4-a716-446655440000\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"uuid\", operator: Operators.UUID }],\n          },\n        ];\n        const data = { uuid: \"123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"uuid\", operator: Operators.UUID }],\n          },\n        ];\n        const data = { uuid: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS ALPHA OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isAlphaOperator\", () => {\n    it(\"should return true for a valid alpha\", () => {\n      const text = \"abc\";\n      expect(isAlphaOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = \"123\";\n      expect(isAlphaOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"123abc\";\n      expect(isAlphaOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isAlpha Operator\", () => {\n      it(\"should return true for a valid alpha\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"alpha\", operator: Operators.Alpha }],\n          },\n        ];\n        const data = { alpha: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"alpha\", operator: Operators.Alpha }],\n          },\n        ];\n        const data = { alpha: \"123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"alpha\", operator: Operators.Alpha }],\n          },\n        ];\n        const data = { alpha: \"123abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS PERSIAN ALPHA OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isPersianAlphaOperator\", () => {\n    it(\"should return true for a valid persian alpha\", () => {\n      const text = \"پارسی\";\n      expect(isPersianAlphaOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = \"123\";\n      expect(isPersianAlphaOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"123پارسی\";\n      expect(isPersianAlphaOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string contains persian alpha as string\", () => {\n      const text = \"persian\";\n      expect(isPersianAlphaOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isPersianAlpha Operator\", () => {\n      it(\"should return true for a valid persian alpha\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"persian\", operator: Operators.PersianAlpha }],\n          },\n        ];\n        const data = { persian: \"پارسی\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"persian\", operator: Operators.PersianAlpha }],\n          },\n        ];\n        const data = { persian: \"۱۲۳\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"persian\", operator: Operators.PersianAlpha }],\n          },\n        ];\n        const data = { persian: \"123پارسی\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string contains persian alpha as string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"persian\", operator: Operators.PersianAlpha }],\n          },\n        ];\n        const data = { persian: \"persian\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS ALPHA NUMERIC OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isAlphaNumericOperator\", () => {\n    it(\"should return true for a valid alpha numeric\", () => {\n      const text = \"abc123\";\n      expect(isAlphaNumericOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc123$\";\n      expect(isAlphaNumericOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string contains alpha numeric as string\", () => {\n      const text = \"alpha numeric\";\n      expect(isAlphaNumericOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isAlphaNumeric Operator\", () => {\n      it(\"should return true for a valid alpha numeric\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"alphaNumeric\", operator: Operators.AlphaNumeric }],\n          },\n        ];\n        const data = { alphaNumeric: \"abc123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"alphaNumeric\", operator: Operators.AlphaNumeric }],\n          },\n        ];\n        const data = { alphaNumeric: \"abc123$\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string contains alpha numeric as string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"alphaNumeric\", operator: Operators.AlphaNumeric }],\n          },\n        ];\n        const data = { alphaNumeric: \"alpha numeric\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS PERSIAN ALPHA NUMERIC OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isPersianAlphaNumericOperator\", () => {\n    it(\"should return true for a valid persian alpha numeric\", () => {\n      const text = \"پارسی۱۲۳\";\n      expect(isPersianAlphaNumericOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"پارسی۱۲۳$a\";\n      expect(isPersianAlphaNumericOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string contains persian alpha numeric as string\", () => {\n      const text = \"persian alpha numeric\";\n      expect(isPersianAlphaNumericOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isPersianAlphaNumeric Operator\", () => {\n      it(\"should return true for a valid persian alpha numeric\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"persianAlphaNumeric\",\n                operator: Operators.PersianAlphaNumeric,\n              },\n            ],\n          },\n        ];\n        const data = { persianAlphaNumeric: \"پارسی۱۲۳\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"persianAlphaNumeric\",\n                operator: Operators.PersianAlphaNumeric,\n              },\n            ],\n          },\n        ];\n        const data = { persianAlphaNumeric: \"پارسی۱۲۳$a\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string contains persian alpha numeric as string\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"persianAlphaNumeric\",\n                operator: Operators.PersianAlphaNumeric,\n              },\n            ],\n          },\n        ];\n        const data = { persianAlphaNumeric: \"persian alpha numeric\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS LOWER CASE OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isLowerCaseOperator\", () => {\n    it(\"should return true for a valid lower case\", () => {\n      const text = \"abc\";\n      expect(isLowerCaseOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"ABC\";\n      expect(isLowerCaseOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string contains lower case as string\", () => {\n      const text = \"lower case\";\n      expect(isLowerCaseOperator(text)).toBeTruthy();\n    });\n\n    describe(\"isLowerCase Operator\", () => {\n      it(\"should return true for a valid lower case\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"lowerCase\", operator: Operators.LowerCase }],\n          },\n        ];\n        const data = { lowerCase: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"lowerCase\", operator: Operators.LowerCase }],\n          },\n        ];\n        const data = { lowerCase: \"ABC\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return true for a string contains lower case as string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"lowerCase\", operator: Operators.LowerCase }],\n          },\n        ];\n        const data = { lowerCase: \"lower case\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS UPPER CASE OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isUpperCaseOperator\", () => {\n    it(\"should return true for a valid upper case\", () => {\n      const text = \"ABC\";\n      expect(isUpperCaseOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isUpperCaseOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string contains upper case as string\", () => {\n      const text = \"upper case\";\n      expect(isUpperCaseOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isUpperCase Operator\", () => {\n      it(\"should return true for a valid upper case\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"upperCase\", operator: Operators.UpperCase }],\n          },\n        ];\n        const data = { upperCase: \"ABC\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"upperCase\", operator: Operators.UpperCase }],\n          },\n        ];\n        const data = { upperCase: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string contains upper case as string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"upperCase\", operator: Operators.UpperCase }],\n          },\n        ];\n        const data = { upperCase: \"upper case\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS STRING OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isStringOperator\", () => {\n    it(\"should return true for a string\", () => {\n      const text = \"abc\";\n      expect(isStringOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = 123;\n      expect(isStringOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a boolean\", () => {\n      const text = true;\n      expect(isStringOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isString Operator\", () => {\n      it(\"should return true for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"string\", operator: Operators.String }],\n          },\n        ];\n        const data = { string: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"string\", operator: Operators.String }],\n          },\n        ];\n        const data = { string: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a boolean\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"string\", operator: Operators.String }],\n          },\n        ];\n        const data = { string: true };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS OBJECT OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isObjectOperator\", () => {\n    it(\"should return true for an object\", () => {\n      const text = { key: \"value\" };\n      expect(isObjectOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isObjectOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = 123;\n      expect(isObjectOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isObject Operator\", () => {\n      it(\"should return true for an object\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"object\", operator: Operators.Object }],\n          },\n        ];\n        const data = { object: { key: \"value\" } };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"object\", operator: Operators.Object }],\n          },\n        ];\n        const data = { object: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"object\", operator: Operators.Object }],\n          },\n        ];\n        const data = { object: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS ARRAY OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isArrayOperator\", () => {\n    it(\"should return true for an array\", () => {\n      const text = [1, 2, 3];\n      expect(isArrayOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isArrayOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = 123;\n      expect(isArrayOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isArray Operator\", () => {\n      it(\"should return true for an array\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"array\", operator: Operators.Array }],\n          },\n        ];\n        const data = { array: [1, 2, 3] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"array\", operator: Operators.Array }],\n          },\n        ];\n        const data = { array: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"array\", operator: Operators.Array }],\n          },\n        ];\n        const data = { array: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS BOOLEAN STRING OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isBooleanStringOperator\", () => {\n    it(\"should return true for a valid boolean string\", () => {\n      const text = \"true\";\n      expect(isBooleanStringOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isBooleanStringOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = \"123\";\n      expect(isBooleanStringOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isBooleanString Operator\", () => {\n      it(\"should return true for a valid boolean string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"boolStr\", operator: Operators.BooleanString }],\n          },\n        ];\n        const data = { boolStr: \"true\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"boolStr\", operator: Operators.BooleanString }],\n          },\n        ];\n        const data = { boolStr: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"boolStr\", operator: Operators.BooleanString }],\n          },\n        ];\n        const data = { boolStr: \"123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS BOOLEAN NUMBER OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isBooleanNumberOperator\", () => {\n    it(\"should return true for a valid boolean number\", () => {\n      const text = 1;\n      expect(isBooleanNumberOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isBooleanNumberOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = 123;\n      expect(isBooleanNumberOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isBooleanNumber Operator\", () => {\n      it(\"should return true for a valid boolean number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"boolNum\", operator: Operators.BooleanNumber }],\n          },\n        ];\n        const data = { boolNum: 1 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"boolNum\", operator: Operators.BooleanNumber }],\n          },\n        ];\n        const data = { boolNum: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"boolNum\", operator: Operators.BooleanNumber }],\n          },\n        ];\n        const data = { boolNum: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS BOOLEAN NUMBER STRING OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isBooleanNumberStringOperator\", () => {\n    it(\"should return true for a valid boolean number string\", () => {\n      const text = \"1\";\n      expect(isBooleanNumberStringOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isBooleanNumberStringOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = 123;\n      expect(isBooleanNumberStringOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isBooleanNumberString Operator\", () => {\n      it(\"should return true for a valid boolean number string\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"boolNumStr\", operator: Operators.BooleanNumberString },\n            ],\n          },\n        ];\n        const data = { boolNumStr: \"1\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { boolNumStr: \"0\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n\n        const data3 = { boolNumStr: \"true\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeFalsy();\n\n        const data4 = { boolNumStr: \"false\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"boolNumStr\", operator: Operators.BooleanNumberString },\n            ],\n          },\n        ];\n        const data = { boolNumStr: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"boolNumStr\", operator: Operators.BooleanNumberString },\n            ],\n          },\n        ];\n        const data = { boolNumStr: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS NUMBER OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isNumberOperator\", () => {\n    it(\"should return true for a number\", () => {\n      const text = 123;\n      expect(isNumberOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isNumberOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a boolean\", () => {\n      const text = true;\n      expect(isNumberOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a NaN\", () => {\n      const text = Number.NaN;\n      expect(isNumberOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isNumber Operator\", () => {\n      it(\"should return true for a number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"number\", operator: Operators.Number }],\n          },\n        ];\n        const data = { number: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { number: 123.45 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n\n        const data3 = { number: \"123\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n\n        const data4 = { number: \"123.45\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeTruthy();\n\n        const data5 = { number: true };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data5),\n        ).toBeFalsy();\n\n        const data6 = { number: false };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data6),\n        ).toBeFalsy();\n\n        const data7 = { number: null };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data7),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"number\", operator: Operators.Number }],\n          },\n        ];\n        const data = { number: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a boolean\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"number\", operator: Operators.Number }],\n          },\n        ];\n        const data = { number: true };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS INTEGER OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isIntegerOperator\", () => {\n    it(\"should return true for an integer\", () => {\n      const text = 123;\n      expect(isIntegerOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a float\", () => {\n      const text = 123.45;\n      expect(isIntegerOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isIntegerOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isInteger Operator\", () => {\n      it(\"should return true for an integer\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"integer\", operator: Operators.Integer }],\n          },\n        ];\n        const data = { integer: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a float\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"integer\", operator: Operators.Integer }],\n          },\n        ];\n        const data = { integer: 123.45 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"integer\", operator: Operators.Integer }],\n          },\n        ];\n        const data = { integer: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS FLOAT OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isFloatOperator\", () => {\n    it(\"should return true for a float\", () => {\n      const text = 123.45;\n      expect(isFloatOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for an integer\", () => {\n      const text = 123;\n      expect(isFloatOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isFloatOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isFloat Operator\", () => {\n      it(\"should return true for a float\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"float\", operator: Operators.Float }],\n          },\n        ];\n        const data = { float: 123.45 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for an integer\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"float\", operator: Operators.Float }],\n          },\n        ];\n        const data = { float: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"float\", operator: Operators.Float }],\n          },\n        ];\n        const data = { float: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS POSITIVE OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isPositiveOperator\", () => {\n    it(\"should return true for a positive number\", () => {\n      const text = 123;\n      expect(isPositiveOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a negative number\", () => {\n      const text = -123;\n      expect(isPositiveOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isPositiveOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isPositive Operator\", () => {\n      it(\"should return true for a positive number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"positive\", operator: Operators.Positive }],\n          },\n        ];\n        const data = { positive: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a negative number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"positive\", operator: Operators.Positive }],\n          },\n        ];\n        const data = { positive: -123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"positive\", operator: Operators.Positive }],\n          },\n        ];\n        const data = { positive: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS NEGATIVE OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isNegativeOperator\", () => {\n    it(\"should return true for a negative number\", () => {\n      const text = -123;\n      expect(isNegativeOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a positive number\", () => {\n      const text = 123;\n      expect(isNegativeOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isNegativeOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isNegative Operator\", () => {\n      it(\"should return true for a negative number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"negative\", operator: Operators.Negative }],\n          },\n        ];\n        const data = { negative: -123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a positive number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"negative\", operator: Operators.Negative }],\n          },\n        ];\n        const data = { negative: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"negative\", operator: Operators.Negative }],\n          },\n        ];\n        const data = { negative: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS ZERO OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isZeroOperator\", () => {\n    it(\"should return true for zero\", () => {\n      const text = 0;\n      expect(isZeroOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a positive number\", () => {\n      const text = 123;\n      expect(isZeroOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a negative number\", () => {\n      const text = -123;\n      expect(isZeroOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      expect(isZeroOperator(text)).toBeFalsy();\n    });\n\n    describe(\"isZero Operator\", () => {\n      it(\"should return true for zero\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"zero\", operator: Operators.Zero }],\n          },\n        ];\n        const data = { zero: 0 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a positive number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"zero\", operator: Operators.Zero }],\n          },\n        ];\n        const data = { zero: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a negative number\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"zero\", operator: Operators.Zero }],\n          },\n        ];\n        const data = { zero: -123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"zero\", operator: Operators.Zero }],\n          },\n        ];\n        const data = { zero: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS NUMBER BETWEEN OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isNumberBetweenOperator\", () => {\n    it(\"should return true for a number between the range\", () => {\n      const text = 5;\n      const min = 1;\n      const max = 10;\n      expect(isNumberBetweenOperator(text, [min, max])).toBeTruthy();\n    });\n    it(\"should return false for a number outside the range\", () => {\n      const text = 15;\n      const min = 1;\n      const max = 10;\n      expect(isNumberBetweenOperator(text, [min, max])).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      const min = 1;\n      const max = 10;\n      expect(isNumberBetweenOperator(text, [min, max])).toBeFalsy();\n    });\n\n    describe(\"isNumberBetween Operator\", () => {\n      it(\"should return true for a number between the range\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"numberBetween\",\n                operator: Operators.NumberBetween,\n                value: [1, 10],\n              },\n            ],\n          },\n        ];\n        const data = { numberBetween: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a number outside the range\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"numberBetween\",\n                operator: Operators.NumberBetween,\n                value: [1, 10],\n              },\n            ],\n          },\n        ];\n        const data = { numberBetween: 15 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"numberBetween\",\n                operator: Operators.NumberBetween,\n                value: [1, 10],\n              },\n            ],\n          },\n        ];\n        const data = { numberBetween: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS STRING LENGTH OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isStringLengthOperator\", () => {\n    it(\"should return true for a string with the correct length\", () => {\n      const text = \"abc\";\n      const length = 3;\n      expect(isLengthOperator(text, length)).toBeTruthy();\n    });\n    it(\"should return false for a string with the incorrect length\", () => {\n      const text = \"abc\";\n      const length = 5;\n      expect(isLengthOperator(text, length)).toBeFalsy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = 123;\n      const length = 3;\n      expect(isLengthOperator(text, length)).toBeFalsy();\n    });\n\n    describe(\"isStringLength Operator\", () => {\n      it(\"should return true for a string with the correct length\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"stringLength\",\n                operator: Operators.StringLength,\n                value: 3,\n              },\n            ],\n          },\n        ];\n        const data = { stringLength: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string with the incorrect length\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"stringLength\",\n                operator: Operators.StringLength,\n                value: 5,\n              },\n            ],\n          },\n        ];\n        const data = { stringLength: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"stringLength\",\n                operator: Operators.StringLength,\n                value: 3,\n              },\n            ],\n          },\n        ];\n        const data = { stringLength: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS MIN LENGTH OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isMinLengthOperator\", () => {\n    it(\"should return true for a string with the correct length\", () => {\n      const text = \"abc\";\n      const length = 3;\n      expect(isMinLengthOperator(text, length)).toBeTruthy();\n    });\n    it(\"should return false for a string with the incorrect length\", () => {\n      const text = \"abc\";\n      const length = 5;\n      expect(isMinLengthOperator(text, length)).toBeFalsy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = 123;\n      const length = 3;\n      expect(isMinLengthOperator(text, length)).toBeFalsy();\n    });\n\n    describe(\"isMinLength Operator\", () => {\n      it(\"should return true for a string with the correct length\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"minLength\", operator: Operators.MinLength, value: 3 },\n            ],\n          },\n        ];\n        const data = { minLength: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string with the incorrect length\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"minLength\", operator: Operators.MinLength, value: 5 },\n            ],\n          },\n        ];\n        const data = { minLength: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"minLength\", operator: Operators.MinLength, value: 3 },\n            ],\n          },\n        ];\n        const data = { minLength: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS MAX LENGTH OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isMaxLengthOperator\", () => {\n    it(\"should return true for a string with the correct length\", () => {\n      const text = \"abc\";\n      const length = 3;\n      expect(isMaxLengthOperator(text, length)).toBeTruthy();\n    });\n    it(\"should return false for a string with the incorrect length\", () => {\n      const text = \"abc\";\n      const length = 2;\n      expect(isMaxLengthOperator(text, length)).toBeFalsy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = 123;\n      const length = 3;\n      expect(isMaxLengthOperator(text, length)).toBeFalsy();\n    });\n\n    describe(\"isMaxLength Operator\", () => {\n      it(\"should return true for a string with the correct length\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"maxLength\", operator: Operators.MaxLength, value: 3 },\n            ],\n          },\n        ];\n        const data = { maxLength: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string with the incorrect length\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"maxLength\", operator: Operators.MaxLength, value: 2 },\n            ],\n          },\n        ];\n        const data = { maxLength: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"maxLength\", operator: Operators.MaxLength, value: 3 },\n            ],\n          },\n        ];\n        const data = { maxLength: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS BETWEEN LENGTH OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isBetweenLengthOperator\", () => {\n    it(\"should return true for a string with the correct length\", () => {\n      const text = \"abc\";\n      const min = 1;\n      const max = 5;\n      expect(IsLengthBetweenOperator(text, [min, max])).toBeTruthy();\n    });\n    it(\"should return false for a string with the incorrect length\", () => {\n      const text = \"abc\";\n      const min = 5;\n      const max = 10;\n      expect(IsLengthBetweenOperator(text, [min, max])).toBeFalsy();\n    });\n    it(\"should return false for a number\", () => {\n      const text = 123;\n      const min = 1;\n      const max = 5;\n      expect(IsLengthBetweenOperator(text, [min, max])).toBeFalsy();\n    });\n\n    describe(\"isBetweenLength Operator\", () => {\n      it(\"should return true for a string with the correct length\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"betweenLength\",\n                operator: Operators.LengthBetween,\n                value: [1, 5],\n              },\n            ],\n          },\n        ];\n        const data = { betweenLength: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a string with the incorrect length\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"betweenLength\",\n                operator: Operators.LengthBetween,\n                value: [5, 10],\n              },\n            ],\n          },\n        ];\n        const data = { betweenLength: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a number\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"betweenLength\",\n                operator: Operators.LengthBetween,\n                value: [1, 5],\n              },\n            ],\n          },\n        ];\n        const data = { betweenLength: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS MIN OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isMinOperator\", () => {\n    it(\"should return true for a number greater than the minimum\", () => {\n      const text = 5;\n      const min = 1;\n      expect(isMinOperator(text, min)).toBeTruthy();\n    });\n    it(\"should return false for a number less than the minimum\", () => {\n      const text = 5;\n      const min = 10;\n      expect(isMinOperator(text, min)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      const min = 1;\n      expect(isMinOperator(text, min)).toBeFalsy();\n    });\n\n    describe(\"isMin Operator\", () => {\n      it(\"should return true for a number greater than the minimum\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"min\", operator: Operators.Min, value: 1 }],\n          },\n        ];\n        const data = { min: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a number less than the minimum\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"min\", operator: Operators.Min, value: 10 }],\n          },\n        ];\n        const data = { min: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"min\", operator: Operators.Min, value: 1 }],\n          },\n        ];\n        const data = { min: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS MAX OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isMaxOperator\", () => {\n    it(\"should return true for a number less than the maximum\", () => {\n      const text = 5;\n      const max = 10;\n      expect(isMaxOperator(text, max)).toBeTruthy();\n    });\n    it(\"should return false for a number greater than the maximum\", () => {\n      const text = 5;\n      const max = 1;\n      expect(isMaxOperator(text, max)).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      const max = 10;\n      expect(isMaxOperator(text, max)).toBeFalsy();\n    });\n\n    describe(\"isMax Operator\", () => {\n      it(\"should return true for a number less than the maximum\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"max\", operator: Operators.Max, value: 10 }],\n          },\n        ];\n        const data = { max: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a number greater than the maximum\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"max\", operator: Operators.Max, value: 1 }],\n          },\n        ];\n        const data = { max: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"max\", operator: Operators.Max, value: 10 }],\n          },\n        ];\n        const data = { max: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS BETWEEN OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isBetweenOperator\", () => {\n    it(\"should return true for a number between the range\", () => {\n      const text = 5;\n      const min = 1;\n      const max = 10;\n      expect(isBetweenOperator(text, [min, max])).toBeTruthy();\n    });\n    it(\"should return false for a number outside the range\", () => {\n      const text = 15;\n      const min = 1;\n      const max = 10;\n      expect(isBetweenOperator(text, [min, max])).toBeFalsy();\n    });\n    it(\"should return false for a string\", () => {\n      const text = \"abc\";\n      const min = 1;\n      const max = 10;\n      expect(isBetweenOperator(text, [min, max])).toBeFalsy();\n    });\n\n    describe(\"isBetween Operator\", () => {\n      it(\"should return true for a number between the range\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"between\", operator: Operators.Between, value: [1, 10] },\n            ],\n          },\n        ];\n        const data = { between: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a number outside the range\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"between\", operator: Operators.Between, value: [1, 10] },\n            ],\n          },\n        ];\n        const data = { between: 15 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a string\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"between\", operator: Operators.Between, value: [1, 10] },\n            ],\n          },\n        ];\n        const data = { between: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS FALSY OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isFalsyOperator\", () => {\n    it(\"should return true for a falsy value\", () => {\n      const text = false;\n      expect(isFalsyOperator(text)).toBeTruthy();\n      expect(isFalsyOperator(null)).toBeTruthy();\n      expect(isFalsyOperator(undefined)).toBeTruthy();\n      expect(isFalsyOperator(\"\")).toBeTruthy();\n      expect(isFalsyOperator(0)).toBeTruthy();\n      expect(isFalsyOperator(Number.NaN)).toBeTruthy();\n    });\n    it(\"should return false for a truthy values\", () => {\n      const text = \"abc\";\n      expect(isFalsyOperator(text)).toBeFalsy();\n      expect(isFalsyOperator(1)).toBeFalsy();\n      expect(isFalsyOperator({})).toBeFalsy();\n      expect(isFalsyOperator([])).toBeFalsy();\n    });\n\n    describe(\"isFalsy Operator\", () => {\n      it(\"should return true for a falsy value\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"falsy\", operator: Operators.Falsy }],\n          },\n        ];\n        const data = { falsy: false };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { falsy: null };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n\n        const data3 = { falsy: undefined };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n\n        const data4 = { falsy: \"\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeTruthy();\n\n        const data5 = { falsy: 0 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data5),\n        ).toBeTruthy();\n\n        const data6 = { falsy: Number.NaN };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data6),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a truthy values\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"falsy\", operator: Operators.Falsy }],\n          },\n        ];\n        const data = { falsy: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n\n        const data2 = { falsy: 1 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeFalsy();\n\n        const data3 = { falsy: {} };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeFalsy();\n\n        const data4 = { falsy: [] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS TRUTHY OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isTruthyOperator\", () => {\n    it(\"should return true for a truthy value\", () => {\n      const text = true;\n      expect(isTruthyOperator(text)).toBeTruthy();\n      expect(isTruthyOperator(\"abc\")).toBeTruthy();\n      expect(isTruthyOperator(1)).toBeTruthy();\n      expect(isTruthyOperator({})).toBeTruthy();\n      expect(isTruthyOperator([])).toBeTruthy();\n    });\n    it(\"should return false for a falsy value\", () => {\n      const text = false;\n      expect(isTruthyOperator(text)).toBeFalsy();\n      expect(isTruthyOperator(null)).toBeFalsy();\n      expect(isTruthyOperator(undefined)).toBeFalsy();\n      expect(isTruthyOperator(\"\")).toBeFalsy();\n      expect(isTruthyOperator(0)).toBeFalsy();\n      expect(isTruthyOperator(Number.NaN)).toBeFalsy();\n    });\n\n    describe(\"isTruthy Operator\", () => {\n      it(\"should return true for a truthy value\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"truthy\", operator: Operators.Truthy }],\n          },\n        ];\n        const data = { truthy: true };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n\n        const data2 = { truthy: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeTruthy();\n\n        const data3 = { truthy: 1 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeTruthy();\n\n        const data4 = { truthy: {} };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeTruthy();\n\n        const data5 = { truthy: [] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data5),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a falsy value\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"truthy\", operator: Operators.Truthy }],\n          },\n        ];\n        const data = { truthy: false };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n\n        const data2 = { truthy: null };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data2),\n        ).toBeFalsy();\n\n        const data3 = { truthy: undefined };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data3),\n        ).toBeFalsy();\n\n        const data4 = { truthy: \"\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data4),\n        ).toBeFalsy();\n\n        const data5 = { truthy: 0 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data5),\n        ).toBeFalsy();\n\n        const data6 = { truthy: Number.NaN };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data6),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IN OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"inOperator\", () => {\n    it(\"should return true for a value in the list\", () => {\n      const text = \"abc\";\n      const list = [\"abc\", \"def\", \"ghi\"];\n      expect(inOperator(text, list)).toBeTruthy();\n    });\n    it(\"should return false for a value not in the list\", () => {\n      const text = \"xyz\";\n      const list = [\"abc\", \"def\", \"ghi\"];\n      expect(inOperator(text, list)).toBeFalsy();\n    });\n    it(\"should return false for an empty list\", () => {\n      const text = \"abc\";\n      expect(inOperator(text, [])).toBeFalsy();\n    });\n\n    describe(\"in Operator\", () => {\n      it(\"should return true for a value in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"in\",\n                operator: Operators.In,\n                value: [\"abc\", \"def\", \"ghi\"],\n              },\n            ],\n          },\n        ];\n        const data = { in: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a value not in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"in\",\n                operator: Operators.In,\n                value: [\"abc\", \"def\", \"ghi\"],\n              },\n            ],\n          },\n        ];\n        const data = { in: \"xyz\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an empty list\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"in\", operator: Operators.In, value: [] }],\n          },\n        ];\n        const data = { in: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: CONTAINS OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"containsOperator\", () => {\n    it(\"should return true for a value in the list\", () => {\n      const text = [\"abc\", \"def\", \"ghi\"];\n      const value = \"abc\";\n      expect(containsOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for a value not in the list\", () => {\n      const text = [\"abc\", \"def\", \"ghi\"];\n      const value = \"xyz\";\n      expect(containsOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return false for an empty list\", () => {\n      const value = \"abc\";\n      expect(containsOperator([], value)).toBeFalsy();\n    });\n\n    describe(\"contains Operator\", () => {\n      it(\"should return true for a value in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"contains\", operator: Operators.Contains, value: \"abc\" },\n            ],\n          },\n        ];\n        const data = { contains: [\"abc\", \"def\", \"ghi\"] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a value not in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"contains\", operator: Operators.Contains, value: \"xyz\" },\n            ],\n          },\n        ];\n        const data = { contains: [\"abc\", \"def\", \"ghi\"] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an empty list\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"contains\", operator: Operators.Contains, value: \"abc\" },\n            ],\n          },\n        ];\n        const data = { contains: [] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: SELF CONTAINS ALL OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"selfContainsAllOperator\", () => {\n    it(\"should return false for all values in the list\", () => {\n      const text = [\"abc\", \"def\", \"ghi\"];\n      const values = [\"abc\", \"def\"];\n      expect(selfContainsAllOperator(text, values)).toBeFalsy();\n    });\n    it(\"should return false for a value not in the list\", () => {\n      const text = [\"abc\", \"def\", \"ghi\"];\n      const values = [\"abc\", \"xyz\"];\n      expect(selfContainsAllOperator(text, values)).toBeFalsy();\n    });\n    it(\"should return false for an empty list\", () => {\n      const values = [\"abc\"];\n      expect(selfContainsAllOperator([], values)).toBeFalsy();\n    });\n\n    describe(\"selfContainsAll Operator\", () => {\n      it(\"should return false for all values in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"selfContainsAll\",\n                operator: Operators.SelfContainsAll,\n                value: [\"$.a\", \"$.b\"],\n              },\n            ],\n          },\n        ];\n        const data = { selfContainsAll: [\"abc\", \"def\"], a: \"abc\", b: \"def\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a value not in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"selfContainsAll\",\n                operator: Operators.SelfContainsAll,\n                value: [\"$.a\", \"$.b\"],\n              },\n            ],\n          },\n        ];\n        const data = { selfContainsAll: [\"abc\", \"def\"], a: \"abc\", b: \"xyz\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an empty list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"selfContainsAll\",\n                operator: Operators.SelfContainsAll,\n                value: [\"$.a\", \"$.b\"],\n              },\n            ],\n          },\n        ];\n        const data = { selfContainsAll: [], a: \"abc\", b: \"def\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: SELF CONTAINS ANY OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"selfContainsAnyOperator\", () => {\n    it(\"should return false for any value in the list\", () => {\n      const text = [\"abc\", \"def\", \"ghi\"];\n      const values = [\"abc\", \"xyz\"];\n      expect(selfContainsAnyOperator(text, values)).toBeFalsy();\n    });\n    it(\"should return false for a value not in the list\", () => {\n      const text = [\"abc\", \"def\", \"ghi\"];\n      const values = [\"xyz\", \"pqr\"];\n      expect(selfContainsAnyOperator(text, values)).toBeFalsy();\n    });\n    it(\"should return false for an empty list\", () => {\n      const values = [\"abc\"];\n      expect(selfContainsAnyOperator([], values)).toBeFalsy();\n    });\n\n    describe(\"selfContainsAny Operator\", () => {\n      it(\"should return false for any value in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"selfContainsAny\",\n                operator: Operators.SelfContainsAny,\n                value: [\"$.a\", \"$.b\"],\n              },\n            ],\n          },\n        ];\n        const data = { selfContainsAny: [\"abc\", \"def\"], a: \"abc\", b: \"xyz\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for a value not in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"selfContainsAny\",\n                operator: Operators.SelfContainsAny,\n                value: [\"$.a\", \"$.b\"],\n              },\n            ],\n          },\n        ];\n        const data = { selfContainsAny: [\"abc\", \"def\"], a: \"xyz\", b: \"pqr\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an empty list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"selfContainsAny\",\n                operator: Operators.SelfContainsAny,\n                value: [\"$.a\", \"$.b\"],\n              },\n            ],\n          },\n        ];\n        const data = { selfContainsAny: [], a: \"abc\", b: \"def\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: CONTAINS ANY OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"containsAnyOperator\", () => {\n    it(\"should return true for any value in the list\", () => {\n      const text = [\"abc\", \"def\", \"ghi\"];\n      const values = [\"abc\", \"xyz\"];\n      expect(containsAnyOperator(text, values)).toBeTruthy();\n    });\n    it(\"should return false for a value not in the list\", () => {\n      const text = [\"abc\", \"def\", \"ghi\"];\n      const values = [\"xyz\", \"pqr\"];\n      expect(containsAnyOperator(text, values)).toBeFalsy();\n    });\n    it(\"should return false for an empty list\", () => {\n      const values = [\"abc\"];\n      expect(containsAnyOperator([], values)).toBeFalsy();\n    });\n\n    describe(\"containsAny Operator\", () => {\n      it(\"should return true for any value in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"containsAny\",\n                operator: Operators.ContainsAny,\n                value: [\"abc\", \"xyz\"],\n              },\n            ],\n          },\n        ];\n        const data = { containsAny: [\"abc\", \"def\", \"ghi\"] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a value not in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"containsAny\",\n                operator: Operators.ContainsAny,\n                value: [\"xyz\", \"pqr\"],\n              },\n            ],\n          },\n        ];\n        const data = { containsAny: [\"abc\", \"def\", \"ghi\"] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an empty list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"containsAny\",\n                operator: Operators.ContainsAny,\n                value: [\"abc\"],\n              },\n            ],\n          },\n        ];\n        const data = { containsAny: [] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: CONTAINS ALL OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"containsAllOperator\", () => {\n    it(\"should return true for all values in the list\", () => {\n      const text = [\"abc\", \"def\", \"ghi\"];\n      const values = [\"abc\", \"def\"];\n      expect(containsAllOperator(text, values)).toBeTruthy();\n    });\n    it(\"should return false for a value not in the list\", () => {\n      const text = [\"abc\", \"def\", \"ghi\"];\n      const values = [\"abc\", \"xyz\"];\n      expect(containsAllOperator(text, values)).toBeFalsy();\n    });\n    it(\"should return false for an empty list\", () => {\n      const values = [\"abc\"];\n      expect(containsAllOperator([], values)).toBeFalsy();\n    });\n\n    describe(\"containsAll Operator\", () => {\n      it(\"should return true for all values in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"containsAll\",\n                operator: Operators.ContainsAll,\n                value: [\"abc\", \"def\"],\n              },\n            ],\n          },\n        ];\n        const data = { containsAll: [\"abc\", \"def\", \"ghi\"] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a value not in the list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"containsAll\",\n                operator: Operators.ContainsAll,\n                value: [\"abc\", \"xyz\"],\n              },\n            ],\n          },\n        ];\n        const data = { containsAll: [\"abc\", \"def\", \"ghi\"] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an empty list\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"containsAll\",\n                operator: Operators.ContainsAll,\n                value: [\"abc\"],\n              },\n            ],\n          },\n        ];\n        const data = { containsAll: [] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS EMPTY OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isEmptyOperator\", () => {\n    it(\"should return true for an empty value\", () => {\n      const text = \"\";\n      expect(isEmptyOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a non-empty value\", () => {\n      const text = \"abc\";\n      expect(isEmptyOperator(text)).toBeFalsy();\n    });\n  });\n\n  ///////////////////////////\n  // :: EQUALS OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"equalsOperator\", () => {\n    it(\"should return true for equal values\", () => {\n      const text = \"abc\";\n      const value = \"abc\";\n      expect(equalsOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for non-equal values\", () => {\n      const text = \"abc\";\n      const value = \"def\";\n      expect(equalsOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return false for different types\", () => {\n      const text = \"abc\";\n      const value = 123;\n      expect(equalsOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return true for equal numbers\", () => {\n      const text = 123;\n      const value = 123;\n      expect(equalsOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return true for equal boolean values\", () => {\n      const text = true;\n      const value = true;\n      expect(equalsOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for non-equal boolean values\", () => {\n      const text = true;\n      const value = false;\n      expect(equalsOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return false for null or undefined\", () => {\n      expect(equalsOperator(undefined, \"123\")).toBeFalsy();\n      expect(equalsOperator(\"123\", undefined)).toBeFalsy();\n      expect(equalsOperator(undefined, undefined)).toBeFalsy();\n\n      expect(equalsOperator(null, \"123\")).toBeFalsy();\n      expect(equalsOperator(\"123\", null)).toBeFalsy();\n      expect(equalsOperator(null, null)).toBeFalsy();\n    });\n    it(\"should return true for equal date values\", () => {\n      const text = new Date(\"2020-01-01\");\n      const value = new Date(\"2020-01-01\");\n      expect(equalsOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for non-equal date values\", () => {\n      const text = new Date(\"2020-01-01\");\n      const value = new Date(\"2020-01-02\");\n      expect(equalsOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return true for equal object values\", () => {\n      const text = { key: \"value\" };\n      const value = { key: \"value\" };\n      expect(equalsOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for non-equal object values\", () => {\n      const text = { key: \"value\" };\n      const value = { key: \"value2\" };\n      expect(equalsOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return true for equal array values\", () => {\n      const text = [1, 2, 3];\n      const value = [1, 2, 3];\n      expect(equalsOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for non-equal array values\", () => {\n      const text = [1, 2, 3];\n      const value = [1, 2, 4];\n      expect(equalsOperator(text, value)).toBeFalsy();\n    });\n\n    describe(\"equals Operator\", () => {\n      it(\"should return true for equal values\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"equals\", operator: Operators.Equals, value: \"abc\" },\n            ],\n          },\n        ];\n        const data = { equals: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for non-equal values\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"equals\", operator: Operators.Equals, value: \"def\" },\n            ],\n          },\n        ];\n        const data = { equals: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for different types\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"equals\", operator: Operators.Equals, value: 123 }],\n          },\n        ];\n        const data = { equals: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return true for equal numbers\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"equals\", operator: Operators.Equals, value: 123 }],\n          },\n        ];\n        const data = { equals: 123 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return true for equal boolean values\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"equals\", operator: Operators.Equals, value: true }],\n          },\n        ];\n        const data = { equals: true };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for non-equal boolean values\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"equals\", operator: Operators.Equals, value: false },\n            ],\n          },\n        ];\n        const data = { equals: true };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return true for equal date values\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"equals\",\n                operator: Operators.Equals,\n                value: \"2020-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { equals: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for non-equal date values\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"equals\",\n                operator: Operators.Equals,\n                value: \"2020-01-02\",\n              },\n            ],\n          },\n        ];\n        const data = { equals: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return true for equal object values\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"equals\",\n                operator: Operators.Equals,\n                value: { key: \"value\" },\n              },\n            ],\n          },\n        ];\n        const data = { equals: { key: \"value\" } };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for non-equal object values\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"equals\",\n                operator: Operators.Equals,\n                value: { key: \"value2\" },\n              },\n            ],\n          },\n        ];\n        const data = { equals: { key: \"value\" } };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return true for equal array values\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"equals\", operator: Operators.Equals, value: [1, 2, 3] },\n            ],\n          },\n        ];\n        const data = { equals: [1, 2, 3] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for non-equal array values\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"equals\", operator: Operators.Equals, value: [1, 2, 4] },\n            ],\n          },\n        ];\n        const data = { equals: [1, 2, 3] };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: GREATER THAN OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"greaterThanOperator\", () => {\n    it(\"should return true for a greater value\", () => {\n      const text = 5;\n      const value = 1;\n      expect(greaterThanOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for a lesser value\", () => {\n      const text = 5;\n      const value = 10;\n      expect(greaterThanOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return false for an equal value\", () => {\n      const text = 5;\n      const value = 5;\n      expect(greaterThanOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return false for null or undefined or none equal inputs type\", () => {\n      expect(greaterThanOperator(undefined, 5)).toBeFalsy();\n      expect(greaterThanOperator(5, undefined)).toBeFalsy();\n      expect(greaterThanOperator(undefined, undefined)).toBeFalsy();\n\n      expect(greaterThanOperator(null, 5)).toBeFalsy();\n      expect(greaterThanOperator(5, null)).toBeFalsy();\n      expect(greaterThanOperator(null, null)).toBeFalsy();\n      expect(greaterThanOperator(5, \"5\")).toBeFalsy();\n    });\n\n    describe(\"greaterThan Operator\", () => {\n      it(\"should return true for a greater value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"greaterThan\",\n                operator: Operators.GreaterThan,\n                value: 1,\n              },\n            ],\n          },\n        ];\n        const data = { greaterThan: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a lesser value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"greaterThan\",\n                operator: Operators.GreaterThan,\n                value: 10,\n              },\n            ],\n          },\n        ];\n        const data = { greaterThan: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an equal value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"greaterThan\",\n                operator: Operators.GreaterThan,\n                value: 5,\n              },\n            ],\n          },\n        ];\n        const data = { greaterThan: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: GREATER THAN OR EQUAL OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"greaterThanOrEqualOperator\", () => {\n    it(\"should return true for a greater value\", () => {\n      const text = 5;\n      const value = 1;\n      expect(greaterThanOrEqualsOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for a lesser value\", () => {\n      const text = 5;\n      const value = 10;\n      expect(greaterThanOrEqualsOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return true for an equal value\", () => {\n      const text = 5;\n      const value = 5;\n      expect(greaterThanOrEqualsOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for null or undefined\", () => {\n      expect(greaterThanOrEqualsOperator(undefined, 5)).toBeFalsy();\n      expect(greaterThanOrEqualsOperator(5, undefined)).toBeFalsy();\n      expect(greaterThanOrEqualsOperator(undefined, undefined)).toBeFalsy();\n\n      expect(greaterThanOrEqualsOperator(null, 5)).toBeFalsy();\n      expect(greaterThanOrEqualsOperator(5, null)).toBeFalsy();\n      expect(greaterThanOrEqualsOperator(null, null)).toBeFalsy();\n    });\n\n    describe(\"greaterThanOrEqual Operator\", () => {\n      it(\"should return true for a greater value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"greaterThanOrEqual\",\n                operator: Operators.GreaterThanOrEquals,\n                value: 1,\n              },\n            ],\n          },\n        ];\n        const data = { greaterThanOrEqual: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a lesser value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"greaterThanOrEqual\",\n                operator: Operators.GreaterThanOrEquals,\n                value: 10,\n              },\n            ],\n          },\n        ];\n        const data = { greaterThanOrEqual: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return true for an equal value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"greaterThanOrEqual\",\n                operator: Operators.GreaterThanOrEquals,\n                value: 5,\n              },\n            ],\n          },\n        ];\n        const data = { greaterThanOrEqual: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: LESS THAN OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"lessThanOperator\", () => {\n    it(\"should return true for a lesser value\", () => {\n      const text = 5;\n      const value = 10;\n      expect(lessThanOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for a greater value\", () => {\n      const text = 5;\n      const value = 1;\n      expect(lessThanOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return false for an equal value\", () => {\n      const text = 5;\n      const value = 5;\n      expect(lessThanOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return false for null or undefined or none equal inputs type\", () => {\n      expect(lessThanOperator(undefined, 5)).toBeFalsy();\n      expect(lessThanOperator(5, undefined)).toBeFalsy();\n      expect(lessThanOperator(undefined, undefined)).toBeFalsy();\n\n      expect(lessThanOperator(null, 5)).toBeFalsy();\n      expect(lessThanOperator(5, null)).toBeFalsy();\n      expect(lessThanOperator(5, \"5\")).toBeFalsy();\n    });\n\n    describe(\"lessThan Operator\", () => {\n      it(\"should return true for a lesser value\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"lessThan\", operator: Operators.LessThan, value: 10 },\n            ],\n          },\n        ];\n        const data = { lessThan: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a greater value\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"lessThan\", operator: Operators.LessThan, value: 1 },\n            ],\n          },\n        ];\n        const data = { lessThan: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an equal value\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"lessThan\", operator: Operators.LessThan, value: 5 },\n            ],\n          },\n        ];\n        const data = { lessThan: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: LESS THAN OR EQUAL OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"lessThanOrEqualOperator\", () => {\n    it(\"should return true for a lesser value\", () => {\n      const text = 5;\n      const value = 10;\n      expect(lessThanOrEqualsOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for a greater value\", () => {\n      const text = 5;\n      const value = 1;\n      expect(lessThanOrEqualsOperator(text, value)).toBeFalsy();\n    });\n    it(\"should return true for an equal value\", () => {\n      const text = 5;\n      const value = 5;\n      expect(lessThanOrEqualsOperator(text, value)).toBeTruthy();\n    });\n    it(\"should return false for null or undefined\", () => {\n      expect(lessThanOrEqualsOperator(undefined, 5)).toBeFalsy();\n      expect(lessThanOrEqualsOperator(5, undefined)).toBeFalsy();\n      expect(lessThanOrEqualsOperator(undefined, undefined)).toBeFalsy();\n\n      expect(lessThanOrEqualsOperator(null, 5)).toBeFalsy();\n      expect(lessThanOrEqualsOperator(5, null)).toBeFalsy();\n      expect(lessThanOrEqualsOperator(null, null)).toBeFalsy();\n    });\n\n    describe(\"lessThanOrEqual Operator\", () => {\n      it(\"should return true for a lesser value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"lessThanOrEqual\",\n                operator: Operators.LessThanOrEquals,\n                value: 10,\n              },\n            ],\n          },\n        ];\n        const data = { lessThanOrEqual: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a greater value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"lessThanOrEqual\",\n                operator: Operators.LessThanOrEquals,\n                value: 1,\n              },\n            ],\n          },\n        ];\n        const data = { lessThanOrEqual: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return true for an equal value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"lessThanOrEqual\",\n                operator: Operators.LessThanOrEquals,\n                value: 5,\n              },\n            ],\n          },\n        ];\n        const data = { lessThanOrEqual: 5 };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS Existent In Object OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isExistentInObjectOperator\", () => {\n    it(\"should return true for a value in the object\", () => {\n      const key = \"key\";\n      const obj = { key: \"abc\" };\n      expect(isExistsInObjectOperator(key, obj)).toBeTruthy();\n    });\n    it(\"should return false for a value not in the object\", () => {\n      const text = \"xyz\";\n      const obj = { key: \"abc\" };\n      expect(isExistsInObjectOperator(text, obj)).toBeFalsy();\n    });\n    it(\"should return false for an empty object\", () => {\n      const text = \"abc\";\n      const obj = {};\n      expect(isExistsInObjectOperator(text, obj)).toBeFalsy();\n    });\n    it(\"should return false for a non-object\", () => {\n      const text = \"abc\";\n      const obj = \"abc\";\n      expect(isExistsInObjectOperator(text, obj)).toBeFalsy();\n    });\n    it(\"should return false for a non-string value\", () => {\n      const text = 123;\n      const obj = { key: \"abc\" };\n      expect(isExistsInObjectOperator(text, obj)).toBeFalsy();\n    });\n    it(\"should return false for a non-string key\", () => {\n      const text = \"abc\";\n      const obj = { key: 123 };\n      expect(isExistsInObjectOperator(text, obj)).toBeFalsy();\n    });\n    it(\"should return false for none object\", () => {\n      const text = \"abc\";\n      const obj = \"abc\";\n      expect(isExistsInObjectOperator(text, obj)).toBeFalsy();\n    });\n\n    describe(\"isExistentInObject Operator\", () => {\n      it(\"should return true for a value in the object\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"$.isExistentInObject.key\", operator: Operators.Exists },\n            ],\n          },\n        ];\n        const data = { isExistentInObject: { key: \"abc\" } };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a value not in the object\", async () => {\n        const conditions = [\n          {\n            and: [\n              { field: \"$.isExistentInObject.key\", operator: Operators.Exists },\n            ],\n          },\n        ];\n        const data = { isExistentInObject: {} };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an empty object\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isExistentInObject\",\n                operator: Operators.Exists,\n                value: \"abc\",\n              },\n            ],\n          },\n        ];\n        const data = { isExistentInObject: {} };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a non-object\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isExistentInObject\",\n                operator: Operators.Exists,\n                value: \"abc\",\n              },\n            ], // value will be ignored\n          },\n        ];\n        const data = { isExistentInObject: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return true for a nested field selection on criteria\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"$.data.field\", operator: Operators.Exists }],\n          },\n        ];\n        const data = {\n          data: {\n            field: \"test\",\n          },\n        };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a nested missing field selection on criteria\", async () => {\n        const conditions = [\n          {\n            and: [{ field: \"$.data.field\", operator: Operators.Exists }],\n          },\n        ];\n        const data = {\n          data: {\n            fieldB: \"test\",\n          },\n        };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS NULL OR UNDEFINED OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isNullOrUndefinedOperator\", () => {\n    it(\"should return true for a null value\", () => {\n      const text = null;\n      expect(isNullOrUndefinedOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a non-null value\", () => {\n      const text = \"abc\";\n      expect(isNullOrUndefinedOperator(text)).toBeFalsy();\n    });\n    it(\"should return false for an undefined value\", () => {\n      const text = undefined;\n      expect(isNullOrUndefinedOperator(text)).toBeTruthy();\n    });\n    it(\"should return false for a non-undefined value\", () => {\n      const text = \"abc\";\n      expect(isNullOrUndefinedOperator(text)).toBeFalsy();\n      expect(isNullOrUndefinedOperator(0)).toBeFalsy();\n      expect(isNullOrUndefinedOperator(false)).toBeFalsy();\n      expect(isNullOrUndefinedOperator(\"\")).toBeFalsy();\n    });\n\n    describe(\"isNullOrUndefined Operator\", () => {\n      it(\"should return true for a null value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isNullOrUndefined\",\n                operator: Operators.NullOrUndefined,\n              },\n            ],\n          },\n        ];\n        const data = { isNullOrUndefined: null };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a non-null value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isNullOrUndefined\",\n                operator: Operators.NullOrUndefined,\n              },\n            ],\n          },\n        ];\n        const data = { isNullOrUndefined: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return true for an undefined value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isNullOrUndefined\",\n                operator: Operators.NullOrUndefined,\n              },\n            ],\n          },\n        ];\n        const data = { isNullOrUndefined: undefined };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a non-undefined value\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isNullOrUndefined\",\n                operator: Operators.NullOrUndefined,\n              },\n            ],\n          },\n        ];\n        const data = { isNullOrUndefined: \"abc\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS DATE AFTER OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isDateAfterOperator\", () => {\n    it(\"should return true for a date after the specified date\", () => {\n      const dateA = new Date(\"2020-01-01\");\n      const dateB = new Date(\"2019-01-01\");\n      expect(isDateAfterOperator(dateA, dateB)).toBeTruthy();\n    });\n    it(\"should return false for a date before the specified date\", () => {\n      const dateA = new Date(\"2020-01-01\");\n      const dateB = new Date(\"2021-01-01\");\n      expect(isDateAfterOperator(dateA, dateB)).toBeFalsy();\n    });\n    it(\"should return false for an equal date\", () => {\n      const dateA = new Date(\"2020-01-01\");\n      const dateB = new Date(\"2020-01-01\");\n      expect(isDateAfterOperator(dateA, dateB)).toBeFalsy();\n    });\n    it(\"should return false for an invalid date of second argument\", () => {\n      const dateA = new Date(\"2020-01-01\");\n      const dateB = new Date(\"invalid\");\n      expect(isDateAfterOperator(dateA, dateB)).toBeFalsy();\n    });\n    it(\"should return false for an invalid date of first argument\", () => {\n      const dateA = new Date(\"invalid\");\n      const dateB = new Date(\"2020-01-01\");\n      expect(isDateAfterOperator(dateA, dateB)).toBeFalsy();\n    });\n    it(\"should return false for an invalid date of both arguments\", () => {\n      const dateA = new Date(\"invalid\");\n      const dateB = new Date(\"invalid\");\n      expect(isDateAfterOperator(dateA, dateB)).toBeFalsy();\n    });\n\n    describe(\"isDateAfter Operator\", () => {\n      it(\"should return true for a date after the specified date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateAfter\",\n                operator: Operators.DateAfter,\n                value: \"2020-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateAfter: \"2021-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a date before the specified date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateAfter\",\n                operator: Operators.DateAfter,\n                value: \"2021-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateAfter: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an equal date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateAfter\",\n                operator: Operators.DateAfter,\n                value: \"2020-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateAfter: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an invalid date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateAfter\",\n                operator: Operators.DateAfter,\n                value: \"2020-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateAfter: \"invalid\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS DATE BEFORE OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isDateBeforeOperator\", () => {\n    it(\"should return true for a date before the specified date\", () => {\n      const dateA = new Date(\"2020-01-01\");\n      const dateB = new Date(\"2021-01-01\");\n      expect(isDateBeforeOperator(dateA, dateB)).toBeTruthy();\n    });\n    it(\"should return false for a date after the specified date\", () => {\n      const dateA = new Date(\"2020-01-01\");\n      const dateB = new Date(\"2019-01-01\");\n      expect(isDateBeforeOperator(dateA, dateB)).toBeFalsy();\n    });\n    it(\"should return false for an equal date\", () => {\n      const dateA = new Date(\"2020-01-01\");\n      const dateB = new Date(\"2020-01-01\");\n      expect(isDateBeforeOperator(dateA, dateB)).toBeFalsy();\n    });\n    it(\"should return false for an invalid date of second argument\", () => {\n      const dateA = new Date(\"2020-01-01\");\n      const dateB = new Date(\"invalid\");\n      expect(isDateBeforeOperator(dateA, dateB)).toBeFalsy();\n    });\n    it(\"should return false for an invalid date of first argument\", () => {\n      const dateA = new Date(\"invalid\");\n      const dateB = new Date(\"2020-01-01\");\n      expect(isDateBeforeOperator(dateA, dateB)).toBeFalsy();\n    });\n\n    describe(\"isDateBefore Operator\", () => {\n      it(\"should return true for a date before the specified date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateBefore\",\n                operator: Operators.DateBefore,\n                value: \"2021-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateBefore: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a date after the specified date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateBefore\",\n                operator: Operators.DateBefore,\n                value: \"2019-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateBefore: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an equal date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateBefore\",\n                operator: Operators.DateBefore,\n                value: \"2020-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateBefore: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an invalid date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateBefore\",\n                operator: Operators.DateBefore,\n                value: \"2020-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateBefore: \"invalid\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS DATE AFTER OR EQUAL OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isDateAfterOrEqualOperator\", () => {\n    it(\"should return true for a date after the specified date\", () => {\n      const text = \"2020-01-01\";\n      const date = \"2019-01-01\";\n      expect(isDateAfterOrEqualsOperator(text, date)).toBeTruthy();\n    });\n    it(\"should return true for an equal date\", () => {\n      const text = \"2020-01-01\";\n      const date = \"2020-01-01\";\n      expect(isDateAfterOrEqualsOperator(text, date)).toBeTruthy();\n    });\n    it(\"should return false for a date before the specified date\", () => {\n      const text = \"2020-01-01\";\n      const date = \"2021-01-01\";\n      expect(isDateAfterOrEqualsOperator(text, date)).toBeFalsy();\n    });\n\n    describe(\"isDateAfterOrEqual Operator\", () => {\n      it(\"should return true for a date after the specified date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateAfterOrEqual\",\n                operator: Operators.DateAfterOrEquals,\n                value: \"2019-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateAfterOrEqual: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return true for an equal date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateAfterOrEqual\",\n                operator: Operators.DateAfterOrEquals,\n                value: \"2020-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateAfterOrEqual: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a date before the specified date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateAfterOrEqual\",\n                operator: Operators.DateAfterOrEquals,\n                value: \"2021-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateAfterOrEqual: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an invalid date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateAfterOrEqual\",\n                operator: Operators.DateAfterOrEquals,\n                value: \"2020-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateAfterOrEqual: \"invalid\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS DATE BEFORE OR EQUAL OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isDateBeforeOrEqualOperator\", () => {\n    it(\"should return true for a date before the specified date\", () => {\n      const text = \"2020-01-01\";\n      const date = \"2021-01-01\";\n      expect(isDateBeforeOrEqualsOperator(text, date)).toBeTruthy();\n    });\n    it(\"should return true for an equal date\", () => {\n      const text = \"2020-01-01\";\n      const date = \"2020-01-01\";\n      expect(isDateBeforeOrEqualsOperator(text, date)).toBeTruthy();\n    });\n    it(\"should return false for a date after the specified date\", () => {\n      const text = \"2020-01-01\";\n      const date = \"2019-01-01\";\n      expect(isDateBeforeOrEqualsOperator(text, date)).toBeFalsy();\n    });\n\n    describe(\"isDateBeforeOrEqual Operator\", () => {\n      it(\"should return true for a date before the specified date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateBeforeOrEqual\",\n                operator: Operators.DateBeforeOrEquals,\n                value: \"2021-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateBeforeOrEqual: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return true for an equal date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateBeforeOrEqual\",\n                operator: Operators.DateBeforeOrEquals,\n                value: \"2020-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateBeforeOrEqual: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a date after the specified date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateBeforeOrEqual\",\n                operator: Operators.DateBeforeOrEquals,\n                value: \"2019-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateBeforeOrEqual: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an invalid date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateBeforeOrEqual\",\n                operator: Operators.DateBeforeOrEquals,\n                value: \"2020-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateBeforeOrEqual: \"invalid\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS DATE EQUALS OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isDateEqualsOperator\", () => {\n    it(\"should return true for equal dates\", () => {\n      const text = \"2020-01-01\";\n      const date = \"2020-01-01\";\n      expect(isDateEqualsOperator(text, date)).toBeTruthy();\n    });\n    it(\"should return false for non-equal dates\", () => {\n      const text = \"2020-01-01\";\n      const date = \"2020-01-02\";\n      expect(isDateEqualsOperator(text, date)).toBeFalsy();\n    });\n\n    describe(\"isDateEquals Operator\", () => {\n      it(\"should return true for equal dates\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateEquals\",\n                operator: Operators.DateEquals,\n                value: \"2020-01-01\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateEquals: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for non-equal dates\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateEquals\",\n                operator: Operators.DateEquals,\n                value: \"2020-01-02\",\n              },\n            ],\n          },\n        ];\n        const data = { isDateEquals: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS DATE BETWEEN OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isDateBetweenOperator\", () => {\n    it(\"should return true for a date between the range\", () => {\n      const text = \"2020-01-01\";\n      const min = \"2019-01-01\";\n      const max = \"2021-01-01\";\n      expect(isDateBetweenOperator(text, [min, max])).toBeTruthy();\n    });\n    it(\"should return false for a date outside the range\", () => {\n      const text = \"2020-01-01\";\n      const min = \"2021-01-01\";\n      const max = \"2022-01-01\";\n      expect(isDateBetweenOperator(text, [min, max])).toBeFalsy();\n    });\n\n    describe(\"isDateBetween Operator\", () => {\n      it(\"should return true for a date between the range\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateBetween\",\n                operator: Operators.DateBetween,\n                value: [\"2019-01-01\", \"2021-01-01\"],\n              },\n            ],\n          },\n        ];\n        const data = { isDateBetween: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a date outside the range\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateBetween\",\n                operator: Operators.DateBetween,\n                value: [\"2021-01-01\", \"2022-01-01\"],\n              },\n            ],\n          },\n        ];\n        const data = { isDateBetween: \"2020-01-01\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an invalid date\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isDateBetween\",\n                operator: Operators.DateBetween,\n                value: [\"2019-01-01\", \"2021-01-01\"],\n              },\n            ],\n          },\n        ];\n        const data = { isDateBetween: \"invalid\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS TIME AFTER OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isTimeAfterOperator\", () => {\n    it(\"should return true for a time after the specified time\", () => {\n      const text = \"12:00\";\n      const time = \"11:00\";\n      expect(isTimeAfterOperator(text, time)).toBeTruthy();\n    });\n    it(\"should return false for a time before the specified time\", () => {\n      const text = \"12:00\";\n      const time = \"13:00\";\n      expect(isTimeAfterOperator(text, time)).toBeFalsy();\n    });\n    it(\"should return false for an equal time\", () => {\n      const text = \"12:00\";\n      const time = \"12:00\";\n      expect(isTimeAfterOperator(text, time)).toBeFalsy();\n    });\n\n    describe(\"isTimeAfter Operator\", () => {\n      it(\"should return true for a time after the specified time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeAfter\",\n                operator: Operators.TimeAfter,\n                value: \"11:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeAfter: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a time before the specified time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeAfter\",\n                operator: Operators.TimeAfter,\n                value: \"13:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeAfter: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an equal time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeAfter\",\n                operator: Operators.TimeAfter,\n                value: \"12:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeAfter: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an invalid time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeAfter\",\n                operator: Operators.TimeAfter,\n                value: \"11:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeAfter: \"invalid\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS TIME BEFORE OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isTimeBeforeOperator\", () => {\n    it(\"should return true for a time before the specified time\", () => {\n      const text = \"12:00\";\n      const time = \"13:00\";\n      expect(isTimeBeforeOperator(text, time)).toBeTruthy();\n    });\n    it(\"should return false for a time after the specified time\", () => {\n      const text = \"12:00\";\n      const time = \"11:00\";\n      expect(isTimeBeforeOperator(text, time)).toBeFalsy();\n    });\n    it(\"should return false for an equal time\", () => {\n      const text = \"12:00\";\n      const time = \"12:00\";\n      expect(isTimeBeforeOperator(text, time)).toBeFalsy();\n    });\n\n    describe(\"isTimeBefore Operator\", () => {\n      it(\"should return true for a time before the specified time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeBefore\",\n                operator: Operators.TimeBefore,\n                value: \"13:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeBefore: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a time after the specified time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeBefore\",\n                operator: Operators.TimeBefore,\n                value: \"11:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeBefore: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an equal time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeBefore\",\n                operator: Operators.TimeBefore,\n                value: \"12:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeBefore: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an invalid time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeBefore\",\n                operator: Operators.TimeBefore,\n                value: \"13:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeBefore: \"invalid\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS TIME AFTER OR EQUAL OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isTimeAfterOrEqualOperator\", () => {\n    it(\"should return true for a time after the specified time\", () => {\n      const leftTime = \"12:00\";\n      const rightTime = \"11:00\";\n      expect(isTimeAfterOrEqualsOperator(leftTime, rightTime)).toBeTruthy();\n    });\n    it(\"should return true for an equal time\", () => {\n      const leftTime = \"12:00\";\n      const rightTime = \"12:00\";\n      expect(isTimeAfterOrEqualsOperator(leftTime, rightTime)).toBeTruthy();\n    });\n    it(\"should return false for a time before the specified time\", () => {\n      const leftTime = \"12:00\";\n      const rightTime = \"13:00\";\n      expect(isTimeAfterOrEqualsOperator(leftTime, rightTime)).toBeFalsy();\n    });\n\n    describe(\"isTimeAfterOrEqual Operator\", () => {\n      it(\"should return true for a time after the specified time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeAfterOrEqual\",\n                operator: Operators.TimeAfterOrEquals,\n                value: \"11:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeAfterOrEqual: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return true for an equal time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeAfterOrEqual\",\n                operator: Operators.TimeAfterOrEquals,\n                value: \"12:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeAfterOrEqual: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a time before the specified time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeAfterOrEqual\",\n                operator: Operators.TimeAfterOrEquals,\n                value: \"13:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeAfterOrEqual: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an invalid time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeAfterOrEqual\",\n                operator: Operators.TimeAfterOrEquals,\n                value: \"11:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeAfterOrEqual: \"invalid\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS TIME BEFORE OR EQUAL OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isTimeBeforeOrEqualOperator\", () => {\n    it(\"should return true for a time before the specified time\", () => {\n      const text = \"12:00\";\n      const time = \"13:00\";\n      expect(isTimeBeforeOrEqualsOperator(text, time)).toBeTruthy();\n    });\n    it(\"should return true for an equal time\", () => {\n      const text = \"12:00\";\n      const time = \"12:00\";\n      expect(isTimeBeforeOrEqualsOperator(text, time)).toBeTruthy();\n    });\n    it(\"should return false for a time after the specified time\", () => {\n      const text = \"12:00\";\n      const time = \"11:00\";\n      expect(isTimeBeforeOrEqualsOperator(text, time)).toBeFalsy();\n    });\n\n    it(\"should return false for an invalid time\", () => {\n      const text = \"12:00\";\n      const time = \"invalid\";\n      expect(isTimeBeforeOrEqualsOperator(text, time)).toBeFalsy();\n    });\n\n    describe(\"isTimeBeforeOrEqual Operator\", () => {\n      it(\"should return true for a time before the specified time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeBeforeOrEqual\",\n                operator: Operators.TimeBeforeOrEquals,\n                value: \"13:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeBeforeOrEqual: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return true for an equal time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeBeforeOrEqual\",\n                operator: Operators.TimeBeforeOrEquals,\n                value: \"12:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeBeforeOrEqual: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a time after the specified time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeBeforeOrEqual\",\n                operator: Operators.TimeBeforeOrEquals,\n                value: \"11:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeBeforeOrEqual: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an invalid time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeBeforeOrEqual\",\n                operator: Operators.TimeBeforeOrEquals,\n                value: \"13:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeBeforeOrEqual: \"invalid\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS TIME EQUALS OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isTimeEqualsOperator\", () => {\n    it(\"should return true for equal times\", () => {\n      const text = \"12:00\";\n      const time = \"12:00\";\n      expect(isTimeEqualsOperator(text, time)).toBeTruthy();\n    });\n    it(\"should return false for non-equal times\", () => {\n      const text = \"12:00\";\n      const time = \"13:00\";\n      expect(isTimeEqualsOperator(text, time)).toBeFalsy();\n    });\n\n    it(\"should return false for an invalid time\", () => {\n      const text = \"12:00\";\n      const time = \"invalid\";\n      expect(isTimeEqualsOperator(text, time)).toBeFalsy();\n    });\n\n    describe(\"isTimeEquals Operator\", () => {\n      it(\"should return true for equal times\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeEquals\",\n                operator: Operators.TimeEquals,\n                value: \"12:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeEquals: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for non-equal times\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeEquals\",\n                operator: Operators.TimeEquals,\n                value: \"13:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeEquals: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an invalid time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeEquals\",\n                operator: Operators.TimeEquals,\n                value: \"12:00\",\n              },\n            ],\n          },\n        ];\n        const data = { isTimeEquals: \"invalid\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n\n  ///////////////////////////\n  // :: IS TIME BETWEEN OPERATOR :: //\n  ///////////////////////////\n\n  describe(\"isTimeBetweenOperator\", () => {\n    it(\"should return true for a time between the range\", () => {\n      const text = \"12:00\";\n      const min = \"11:00\";\n      const max = \"13:00\";\n      expect(isTimeBetweenOperator(text, [min, max])).toBeTruthy();\n    });\n    it(\"should return false for a time outside the range\", () => {\n      const text = \"12:00\";\n      const min = \"13:00\";\n      const max = \"14:00\";\n      expect(isTimeBetweenOperator(text, [min, max])).toBeFalsy();\n    });\n\n    it(\"should return false for an invalid time\", () => {\n      const text = \"12:00\";\n      const min = \"invalid\";\n      const max = \"14:00\";\n      expect(isTimeBetweenOperator(text, [min, max])).toBeFalsy();\n    });\n\n    describe(\"isTimeBetween Operator\", () => {\n      it(\"should return true for a time between the range\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeBetween\",\n                operator: Operators.TimeBetween,\n                value: [\"11:00\", \"13:00\"],\n              },\n            ],\n          },\n        ];\n        const data = { isTimeBetween: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeTruthy();\n      });\n\n      it(\"should return false for a time outside the range\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeBetween\",\n                operator: Operators.TimeBetween,\n                value: [\"13:00\", \"14:00\"],\n              },\n            ],\n          },\n        ];\n        const data = { isTimeBetween: \"12:00\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n\n      it(\"should return false for an invalid time\", async () => {\n        const conditions = [\n          {\n            and: [\n              {\n                field: \"isTimeBetween\",\n                operator: Operators.TimeBetween,\n                value: [\"11:00\", \"13:00\"],\n              },\n            ],\n          },\n        ];\n        const data = { isTimeBetween: \"invalid\" };\n        expect(\n          await RuleEngine.getEvaluateResult({ conditions }, data),\n        ).toBeFalsy();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/core/test/rule-engine.spec.ts",
    "content": "import { it, expect, describe, beforeAll } from \"vitest\";\nimport {\n  RuleEngine,\n  registerCustomOperator,\n  OperatorCategory,\n  BaseOperatorStrategy,\n} from \"@root\";\nimport type { OperatorMetadata, OperatorContext } from \"@root\";\n\ndescribe(\"rule engine\", () => {\n  let engine: RuleEngine;\n\n  beforeAll(() => {\n    // Initialize with custom config\n    engine = RuleEngine.getInstance({\n      autoInitializeOperators: true,\n      enableCaching: true,\n      maxCacheSize: 100,\n    });\n  });\n\n  describe(\"basic Evaluation\", () => {\n    it(\"should evaluate simple rules\", async () => {\n      const rule = {\n        conditions: {\n          and: [\n            { field: \"age\", operator: \"greater-than\" as any, value: 18 },\n            { field: \"status\", operator: \"equals\" as any, value: \"active\" },\n          ],\n        },\n      };\n\n      const result = await engine.evaluate(rule, {\n        age: 25,\n        status: \"active\",\n      });\n\n      expect(result).toMatchObject({\n        isPassed: true,\n        value: true,\n      });\n    });\n\n    it(\"should handle array criteria\", async () => {\n      const rule = {\n        conditions: {\n          and: [{ field: \"score\", operator: \"greater-than\" as any, value: 60 }],\n        },\n      };\n\n      const results = await engine.evaluate(rule, [\n        { score: 70 },\n        { score: 50 },\n        { score: 80 },\n      ]);\n\n      expect(Array.isArray(results)).toBe(true);\n      if (Array.isArray(results)) {\n        expect(results).toHaveLength(3);\n        expect(results[0].isPassed).toBe(true);\n        expect(results[1].isPassed).toBe(false);\n        expect(results[2].isPassed).toBe(true);\n      }\n    });\n  });\n\n  describe(\"enhanced Introspection\", () => {\n    it(\"should provide operator metadata\", () => {\n      const rule = {\n        conditions: [\n          {\n            and: [\n              { field: \"name\", operator: \"like\" as any, value: \"John%\" },\n              { field: \"age\", operator: \"between\" as any, value: [18, 65] },\n            ],\n            result: { status: \"eligible\" },\n          },\n        ],\n      };\n\n      // @ts-ignore\n      const introspection = engine.introspect(rule, {\n        includeMetadata: true,\n        includeComplexity: true,\n      });\n\n      expect(introspection.operatorMetadata).toBeDefined();\n      expect(introspection.operatorMetadata?.usedOperators).toContain(\"like\");\n      expect(introspection.operatorMetadata?.usedOperators).toContain(\n        \"between\",\n      );\n\n      expect(introspection.complexity).toBeDefined();\n      expect(introspection.complexity?.totalConstraints).toBe(2);\n      expect(introspection.complexity?.uniqueFields).toBe(2);\n    });\n  });\n\n  describe(\"custom Operators\", () => {\n    // Define a custom postal code operator\n    class PostalCodeOperator extends BaseOperatorStrategy<string, string> {\n      readonly metadata: OperatorMetadata = {\n        name: \"postal-code\" as any,\n        displayName: \"Postal Code\",\n        category: OperatorCategory.PATTERN,\n        description: \"Validates postal codes by country\",\n        acceptedFieldTypes: [\"string\"],\n        expectedValueType: \"string\",\n        requiresValue: true,\n        example: '{ field: \"zipCode\", operator: \"postal-code\", value: \"US\" }',\n      };\n\n      evaluate(context: OperatorContext): boolean {\n        const { fieldValue, constraintValue } = context;\n\n        if (\n          typeof fieldValue !== \"string\" ||\n          typeof constraintValue !== \"string\"\n        ) {\n          return false;\n        }\n\n        const patterns: Record<string, RegExp> = {\n          US: /^\\d{5}(-\\d{4})?$/,\n          UK: /^[A-Z]{1,2}\\d[A-Z\\d]? ?\\d[A-Z]{2}$/i,\n          CA: /^[A-Z]\\d[A-Z] ?\\d[A-Z]\\d$/i,\n          DE: /^\\d{5}$/,\n          FR: /^\\d{5}$/,\n        };\n\n        const pattern = patterns[constraintValue.toUpperCase()];\n        return pattern ? pattern.test(fieldValue) : false;\n      }\n\n      isValidFieldType(value: unknown): value is string {\n        return typeof value === \"string\";\n      }\n\n      isValidConstraintType(value: unknown): value is string {\n        const validCountries = [\"US\", \"UK\", \"CA\", \"DE\", \"FR\"];\n        return (\n          typeof value === \"string\" &&\n          validCountries.includes(value.toUpperCase())\n        );\n      }\n    }\n\n    it(\"should support custom operators\", async () => {\n      // Register custom operator\n      registerCustomOperator(PostalCodeOperator);\n\n      const rule = {\n        conditions: {\n          and: [\n            { field: \"zipCode\", operator: \"postal-code\" as any, value: \"US\" },\n          ],\n        },\n      };\n\n      // Test valid US postal code\n      const result1 = await engine.evaluate(rule, {\n        zipCode: \"12345\",\n      });\n      expect(result1.isPassed).toBe(true);\n\n      // Test invalid US postal code\n      const result2 = await engine.evaluate(rule, { zipCode: \"1234\" });\n      expect(result2.isPassed).toBe(false);\n\n      // Test valid US postal code with +4\n      const result3 = await engine.evaluate(rule, {\n        zipCode: \"12345-6789\",\n      });\n      expect(result3.isPassed).toBe(true);\n    });\n  });\n\n  describe(\"performance Features\", () => {\n    it(\"should cache evaluation results\", async () => {\n      const rule = {\n        conditions: {\n          and: [{ field: \"value\", operator: \"equals\" as any, value: 42 }],\n        },\n      };\n\n      const criteria = { value: 42 };\n\n      // First evaluation\n      const result1 = await engine.evaluate(rule, criteria);\n\n      // Second evaluation (should be cached)\n      const result2 = await engine.evaluate(rule, criteria);\n\n      expect(result1.isPassed).toBe(true);\n      expect(result2.isPassed).toBe(true);\n\n      // Ensure results are the same\n      expect(result1).toEqual(result2);\n      // Cached evaluation should be faster (though timing can be unreliable in tests)\n      // In a real scenario, cached would be significantly faster\n    });\n\n    it(\"should handle trust mode\", async () => {\n      const invalidRule = {\n        conditions: {\n          // Missing operator type\n          and: [{ field: \"test\" }],\n        },\n      } as any;\n\n      // Should throw without trust mode\n      await expect(engine.evaluate(invalidRule, { test: 1 })).rejects.toThrow();\n\n      // Should not throw with trust mode\n      const result = await engine.evaluate(invalidRule, { test: 1 }, true);\n      expect(result).toBeDefined();\n    });\n  });\n\n  describe(\"operator Validation\", () => {\n    it(\"should validate operators in rules\", () => {\n      const rule = {\n        conditions: {\n          and: [\n            { field: \"valid\", operator: \"equals\" as any, value: 1 },\n            { field: \"invalid\", operator: \"non-existent-op\" as any, value: 2 },\n          ],\n        },\n      };\n\n      const validation = engine.validateOperators(rule);\n      expect(validation.isValid).toBe(false);\n      expect(validation.errors).toHaveLength(1);\n      expect(validation.errors[0]).toContain(\"non-existent-op\");\n    });\n\n    it(\"should get used operators\", () => {\n      const rule = {\n        conditions: {\n          or: [\n            { field: \"a\", operator: \"equals\" as any, value: 1 },\n            { field: \"b\", operator: \"greater-than\" as any, value: 2 },\n            {\n              and: [\n                { field: \"c\", operator: \"like\" as any, value: \"test%\" },\n                { field: \"d\", operator: \"between\" as any, value: [1, 10] },\n              ],\n            },\n          ],\n        },\n      };\n\n      const operators = engine.getUsedOperators(rule);\n      expect(operators.size).toBe(4);\n      expect(operators).toContain(\"equals\");\n      expect(operators).toContain(\"greater-than\");\n      expect(operators).toContain(\"like\");\n      expect(operators).toContain(\"between\");\n    });\n  });\n\n  describe(\"type Safety\", () => {\n    it(\"should provide type-safe evaluation results\", async () => {\n      interface UserData {\n        name: string;\n        age: number;\n        isActive: boolean;\n      }\n\n      interface RuleResult {\n        accessLevel: \"admin\" | \"user\" | \"guest\";\n        permissions: string[];\n      }\n\n      const rule = {\n        conditions: [\n          {\n            and: [\n              {\n                field: \"age\",\n                operator: \"greater-than-or-equals\" as any,\n                value: 21,\n              },\n              { field: \"isActive\", operator: \"equals\" as any, value: true },\n            ],\n            result: {\n              value: {\n                accessLevel: \"admin\" as const,\n                permissions: [\"read\", \"write\", \"delete\"],\n              },\n            },\n          },\n        ],\n        default: {\n          value: {\n            accessLevel: \"guest\" as const,\n            permissions: [\"read\"],\n          },\n        },\n      };\n\n      // @ts-ignore\n      const result = await engine.evaluate<RuleResult>(rule, {\n        name: \"John\",\n        age: 25,\n        isActive: true,\n      } as unknown as UserData);\n\n      if (!Array.isArray(result)) {\n        expect(result.value.accessLevel).toBe(\"admin\");\n        expect(result.value.permissions).toContain(\"write\");\n      }\n    });\n  });\n\n  describe(\"backward Compatibility\", () => {\n    it(\"should work with legacy rule format\", async () => {\n      const legacyRule = {\n        conditions: {\n          and: [\n            { field: \"status\", operator: \"equals\" as any, value: \"active\" },\n            { field: \"score\", operator: \"greater-than\" as any, value: 50 },\n          ],\n        },\n      };\n\n      const result = await RuleEngine.evaluate(legacyRule, {\n        status: \"active\",\n        score: 75,\n      });\n\n      expect(result.isPassed).toBe(true);\n    });\n\n    it(\"should support static methods\", async () => {\n      const rule = {\n        conditions: {\n          and: [{ field: \"test\", operator: \"equals\" as any, value: \"value\" }],\n        },\n      };\n\n      // Test static methods\n      const isPassed = await RuleEngine.checkIsPassed(rule, { test: \"value\" });\n      expect(isPassed).toBe(true);\n\n      const value = await RuleEngine.getEvaluateResult(rule, { test: \"value\" });\n      expect(value).toBe(true);\n\n      const validation = RuleEngine.validate(rule);\n      expect(validation.isValid).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/core/test/rulesets/invalid2.json.ts",
    "content": "import type { RuleType, Condition } from \"../../src\";\nimport { Operators } from \"../../src\";\n\nexport const invalid2Json: RuleType = {\n  conditions: [\n    {\n      or: [\n        {\n          and: [\n            {\n              field: \"CountryIso\",\n              operator: Operators.In,\n              value: [\"GB\", \"FI\"],\n            },\n            {\n              field: \"Leverage\",\n              operator: Operators.LessThan,\n              value: 200,\n            },\n            {\n              field: \"Monetization\",\n              operator: Operators.Equals,\n              value: \"Real\",\n            },\n          ],\n        },\n        {\n          field: \"Leverage\",\n          operator: Operators.GreaterThanOrEquals,\n          value: 1000,\n        },\n      ],\n      result: {\n        value: 3,\n      },\n    },\n    {\n      and: [\n        {\n          field: \"Category\",\n          operator: Operators.Equals,\n          value: \"Islamic\",\n        },\n      ],\n      result: {\n        value: 4,\n      },\n    },\n    {\n      foo: \"bar\",\n    } as Condition,\n  ],\n  default: {\n    value: 2,\n  },\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/password-rule.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src\";\n\nexport const PasswordRuleJson: RuleType = {\n  default: {\n    value: false,\n  },\n  conditions: [\n    {\n      and: [\n        {\n          or: [\n            {\n              and: [\n                {\n                  field: \"$.data.username\",\n                  operator: Operators.Exists,\n                },\n                {\n                  field: \"$.payload.password\",\n                  operator: Operators.SelfContainsNone,\n                  value: [\"$.data.username\"],\n                  message: \"رمزعبور نمی‌تواند شامل نام کاربری باشد\",\n                },\n              ],\n            },\n            {\n              and: [\n                {\n                  field: \"$.data.phone\",\n                  operator: Operators.Exists,\n                },\n                {\n                  field: \"$.payload.password\",\n                  operator: Operators.SelfContainsNone,\n                  value: [\"$.data.phone\"],\n                  message: \"رمزعبور نمی‌تواند شامل شماره همراه باشد\",\n                },\n              ],\n            },\n          ],\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.MinLength,\n          value: 8,\n          message: \"رمزعبور باید حداقل ۸ کاراکتر باشد\",\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.MaxLength,\n          value: 32,\n          message: \"رمزعبور باید حداکثر ۳۲ کاراکتر باشد\",\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.Matches,\n          value: \"^(?=.*?[A-Z]).*$\",\n          message: \"رمزعبور باید حداقل شامل یک حرف بزرگ باشد\",\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.Matches,\n          value: \"^(?=.*?[a-z]).*$\",\n          message: \"رمزعبور باید حداقل شامل یک حرف کوچک باشد\",\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.Matches,\n          value: \"^(?=.*?[0-9]).*$\",\n          message: \"رمزعبور باید حداقل شامل یک عدد باشد\",\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.Matches,\n          value: \"^(?=.*?[#?!@$%^&*-]).*$\",\n          message: \"رمزعبور باید حداقل شامل یک کاراکتر خاص باشد\",\n        },\n      ],\n      result: {\n        value: true,\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/regex-rules.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src\";\n\nexport const RegexRulesJson: RuleType = {\n  conditions: [\n    {\n      and: [\n        {\n          field: \"$.payload.password\",\n          operator: Operators.SelfNotContainsAll,\n          value: [\"$.data.username\"],\n          message: \"رمزعبور نمی‌تواند شامل نام کاربری باشد\",\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.MinLength,\n          value: 8,\n          message: \"رمزعبور باید حداقل ۸ کاراکتر باشد\",\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.MaxLength,\n          value: 32,\n          message: \"رمزعبور باید حداکثر ۳۲ کاراکتر باشد\",\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.Matches,\n          value: \"^(?=.*?[A-Z]).*$\",\n          message: \"رمزعبور باید حداقل شامل یک حرف بزرگ باشد\",\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.Matches,\n          value: \"^(?=.*?[a-z]).*$\",\n          message: \"رمزعبور باید حداقل شامل یک حرف کوچک باشد\",\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.Matches,\n          value: \"^(?=.*?[0-9]).*$\",\n          message: \"رمزعبور باید حداقل شامل یک عدد باشد\",\n        },\n        {\n          field: \"$.payload.password\",\n          operator: Operators.Matches,\n          value: \"^(?=.*?[#?!@$%^&*-]).*$\",\n          message: \"رمزعبور باید حداقل شامل یک کاراکتر خاص باشد\",\n        },\n      ],\n      result: {\n        value: true,\n      },\n    },\n  ],\n  default: {\n    value: false,\n  },\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/self-fields-constraints.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src\";\n\nexport const selfFieldsConstraintsJson: RuleType = {\n  conditions: [\n    {\n      and: [\n        {\n          field: \"$.meta.default.password\",\n          operator: Operators.SelfNotContainsAll,\n          value: [\"$.username\", \"$.name\", \"$.family\"],\n        },\n        {\n          field: \"$.meta.default.password\",\n          operator: Operators.NotLike,\n          value: \"^A\",\n        },\n        {\n          field: \"$.meta.default.password\",\n          operator: Operators.Like,\n          value: \"^@A%\",\n        },\n      ],\n      result: {\n        value: true,\n        message: `Password is valid and contains username($.username), name($.name) and family($.family)`,\n      },\n    },\n  ],\n  default: {\n    value: false,\n    message: `Password is invalid and contains username($.username), name($.name) and family($.family)`,\n  },\n};\n\nexport const selfFieldsConstraintsJsonWithNoResult: RuleType = {\n  conditions: [\n    {\n      and: [\n        {\n          field: \"$.meta.default.password\",\n          operator: Operators.SelfNotContainsAll,\n          value: [\"$.username\", \"$.name\", \"$.family\"],\n          message:\n            \"Password is invalid and contains username($.username), name($.name) and family($.family)\",\n        },\n      ],\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid1.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src\";\n\nexport const valid1Json: RuleType = {\n  conditions: {\n    or: [\n      {\n        and: [\n          {\n            field: \"WinRate\",\n            operator: Operators.GreaterThan,\n            value: 60,\n          },\n          {\n            field: \"AverageTradeDuration\",\n            operator: Operators.LessThan,\n            value: 60,\n          },\n          {\n            field: \"Duration\",\n            operator: Operators.GreaterThan,\n            value: 259200,\n          },\n          {\n            field: \"TotalDaysTraded\",\n            operator: Operators.GreaterThanOrEquals,\n            value: 3,\n          },\n        ],\n      },\n      {\n        and: [\n          {\n            field: \"$.payload.ProfitPercentage\",\n            operator: Operators.GreaterThanOrEquals,\n            value: 10,\n          },\n        ],\n      },\n    ],\n  },\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid10.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src\";\n\nexport const Valid10Json: RuleType = {\n  conditions: [\n    {\n      and: [\n        {\n          field: \"age\",\n          operator: Operators.Exists,\n        },\n        {\n          field: \"relationship\",\n          operator: Operators.NotExists,\n        },\n      ],\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid11.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src\";\n\nexport const Valid11Json: RuleType = {\n  conditions: [\n    {\n      and: [\n        {\n          field: \"$.payload.depositAmount\",\n          operator: Operators.LengthBetween,\n          value: [4, 20],\n          message:\n            \"Deposit amount must be between $.self.value[0] and $.self.value[1] characters.\",\n        },\n        {\n          or: [\n            {\n              and: [\n                {\n                  field: \"$.metadata.levelId\",\n                  operator: Operators.Equals,\n                  value: 1,\n                  message:\n                    \"Invalid levelId. Please check the value. Must be $.self.value.\",\n                },\n                {\n                  and: [\n                    // ...\n                  ],\n                },\n              ],\n              result: {\n                value: 1,\n              },\n            },\n            {\n              and: [\n                {\n                  field: \"$.metadata.levelId\",\n                  operator: Operators.Equals,\n                  value: 2,\n                  message:\n                    \"Invalid levelId. Please check the value. Must be $.self.value.\",\n                },\n                {\n                  and: [\n                    // ...\n                  ],\n                },\n              ],\n              result: {\n                value: 2,\n              },\n            },\n            {\n              and: [\n                {\n                  field: \"$.metadata.levelId\",\n                  operator: Operators.Equals,\n                  value: 3,\n                  message:\n                    \"Invalid levelId. Please check the value. Must be $.self.value.\",\n                },\n                {\n                  and: [\n                    // ...\n                  ],\n                },\n              ],\n              result: {\n                value: 3,\n              },\n            },\n          ],\n        },\n      ],\n      result: {\n        value: true,\n        message:\n          \"Valid deposit amount. LevelId is $.metadata.levelId and deposit amount is $.payload.depositAmount.\",\n      },\n    },\n  ],\n  default: {\n    value: false,\n    message:\n      \"Invalid deposit amount. LevelId is $.metadata.levelId and deposit amount is $.payload.depositAmount.\",\n  },\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid12.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src\";\n\nexport const Valid12Json: RuleType = {\n  conditions: [\n    {\n      or: [\n        {\n          and: [\n            {\n              field: \"$.age\",\n              operator: Operators.Equals,\n              value: 18,\n            },\n            {\n              field: \"$.age\",\n              operator: Operators.NotEquals,\n              value: 21,\n            },\n          ],\n        },\n        {\n          and: [\n            {\n              field: \"$.name\",\n              operator: Operators.Like,\n              value: \"*Ali\",\n            },\n            {\n              field: \"$.name\",\n              operator: Operators.NotLike,\n              value: \"*Farzad\",\n            },\n          ],\n        },\n        {\n          and: [\n            {\n              field: \"$.age\",\n              operator: Operators.GreaterThan,\n              value: 10,\n            },\n            {\n              field: \"$.age\",\n              operator: Operators.GreaterThanOrEquals,\n              value: 18,\n            },\n          ],\n        },\n        {\n          and: [\n            {\n              field: \"$.age\",\n              operator: Operators.LessThan,\n              value: 30,\n            },\n            {\n              field: \"$.age\",\n              operator: Operators.LessThanOrEquals,\n              value: 28,\n            },\n          ],\n        },\n        {\n          and: [\n            {\n              field: \"$.name\",\n              operator: Operators.In,\n              value: [\"Ali\", \"Farzad\"],\n            },\n            {\n              field: \"$.name\",\n              operator: Operators.NotIn,\n              value: [\"Reza\", \"Mehdi\"],\n            },\n          ],\n        },\n        {\n          and: [\n            {\n              field: \"$.name\",\n              operator: Operators.Contains,\n              value: \"Ali\",\n            },\n            {\n              field: \"$.name\",\n              operator: Operators.NotContains,\n              value: \"Farzad\",\n            },\n          ],\n        },\n        {\n          and: [\n            {\n              field: \"$.name\",\n              operator: Operators.Matches,\n              value: \"Ali\",\n            },\n            {\n              field: \"$.name\",\n              operator: Operators.NotMatches,\n              value: \"Farzad\",\n            },\n          ],\n        },\n        {\n          and: [\n            {\n              field: \"$.name\",\n              operator: Operators.NullOrUndefined,\n            },\n            {\n              field: \"$.name\",\n              operator: Operators.NotNullOrUndefined,\n            },\n          ],\n        },\n        {\n          and: [\n            {\n              field: \"$.name\",\n              operator: Operators.Empty,\n            },\n            {\n              field: \"$.name\",\n              operator: Operators.NotEmpty,\n            },\n          ],\n        },\n        {\n          and: [\n            {\n              field: \"$.name\",\n              operator: Operators.SelfContainsAll,\n              value: [\"$.secondName\"],\n            },\n            {\n              field: \"$.name\",\n              operator: Operators.SelfNotContainsAll,\n              value: [\"$.name\"],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid13.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src/enums\";\n\nexport const valid13Json: RuleType = {\n  conditions: [\n    {\n      or: [\n        {\n          and: [\n            {\n              field: \"CountryIso\",\n              operator: Operators.In,\n              value: [\"GB\", \"FI\"],\n            },\n            {\n              field: \"Leverage\",\n              operator: Operators.GreaterThan,\n              value: 200,\n            },\n            {\n              field: \"Monetization\",\n              operator: Operators.Equals,\n              value: \"Real\",\n            },\n          ],\n          result: {\n            value: null,\n          },\n        },\n        {\n          and: [\n            {\n              field: \"Leverage\",\n              operator: Operators.GreaterThanOrEquals,\n              value: 1000,\n            },\n          ],\n        },\n      ],\n      result: {\n        value: 3,\n      },\n    },\n    {\n      and: [\n        {\n          field: \"Category\",\n          operator: Operators.Equals,\n          value: \"Islamic\",\n        },\n      ],\n      result: {\n        value: 4,\n      },\n    },\n  ],\n  default: {\n    value: 2,\n  },\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid2.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src\";\n\nexport const valid2Json: RuleType = {\n  conditions: {\n    or: [\n      {\n        and: [\n          {\n            field: \"Leverage\",\n            operator: Operators.LessThanOrEquals,\n            value: 100,\n          },\n          {\n            field: \"WinRate\",\n            operator: Operators.GreaterThan,\n            value: 60,\n          },\n          {\n            field: \"AverageTradeDuration\",\n            operator: Operators.LessThan,\n            value: 60,\n          },\n          {\n            field: \"Duration\",\n            operator: Operators.GreaterThan,\n            value: 259200,\n          },\n          {\n            field: \"TotalDaysTraded\",\n            operator: Operators.GreaterThanOrEquals,\n            value: 3,\n          },\n        ],\n      },\n      {\n        none: [\n          {\n            field: \"AverageTradeDuration\",\n            operator: Operators.NotEquals,\n            value: 10,\n          },\n          {\n            field: \"Foo\",\n            operator: Operators.NotIn,\n            value: [10, 11, 12],\n          },\n        ],\n      },\n    ],\n  },\n} as RuleType;\n"
  },
  {
    "path": "packages/core/test/rulesets/valid3.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src\";\n\nexport const valid3Json: RuleType = {\n  conditions: [\n    {\n      or: [\n        {\n          and: [\n            {\n              field: \"CountryIso\",\n              operator: Operators.In,\n              value: [\"GB\", \"FI\"],\n            },\n            {\n              field: \"Leverage\",\n              operator: Operators.LessThan,\n              value: 200,\n            },\n            {\n              field: \"Monetization\",\n              operator: Operators.Equals,\n              value: \"Real\",\n            },\n          ],\n        },\n        {\n          field: \"Leverage\",\n          operator: Operators.GreaterThanOrEquals,\n          value: 1000,\n        },\n      ],\n      result: {\n        value: 3,\n      },\n    },\n    {\n      and: [\n        {\n          field: \"Category\",\n          operator: Operators.Equals,\n          value: \"Islamic\",\n        },\n      ],\n      result: {\n        value: 4,\n      },\n    },\n  ],\n  default: {\n    value: 2,\n  },\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid4.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src/enums\";\n\nexport const valid4Json: RuleType = {\n  conditions: [\n    {\n      or: [\n        {\n          field: \"Leverage\",\n          operator: Operators.Equals,\n          value: 1000,\n        },\n        {\n          field: \"Leverage\",\n          operator: Operators.Equals,\n          value: 500,\n        },\n        {\n          and: [\n            {\n              field: \"CountryIso\",\n              operator: Operators.Contains,\n              value: [\"GB\", \"FI\"],\n            },\n            {\n              field: \"Monetization\",\n              operator: Operators.Equals,\n              value: \"Real\",\n            },\n            {\n              or: [\n                {\n                  field: \"Category\",\n                  operator: Operators.GreaterThanOrEquals,\n                  value: 1000,\n                },\n                {\n                  field: \"Category\",\n                  operator: Operators.Equals,\n                  value: 22,\n                },\n                {\n                  or: [\n                    {\n                      field: \"Category\",\n                      operator: Operators.Equals,\n                      value: 11,\n                    },\n                    {\n                      field: \"Category\",\n                      operator: Operators.Equals,\n                      value: 12,\n                    },\n                    {\n                      and: [\n                        {\n                          field: \"HasStudentCard\",\n                          operator: Operators.Equals,\n                          value: true,\n                        },\n                        {\n                          field: \"IsUnder18\",\n                          operator: Operators.Equals,\n                          value: true,\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n      result: {\n        value: 3,\n      },\n    },\n    {\n      and: [\n        {\n          field: \"Category\",\n          operator: Operators.Equals,\n          value: \"Islamic\",\n        },\n      ],\n      result: {\n        value: 4,\n      },\n    },\n  ],\n  default: {\n    value: 2,\n  },\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid5.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src\";\n\nexport const valid5Json: RuleType = {\n  conditions: {\n    or: [\n      {\n        field: \"countries\",\n        operator: Operators.Contains,\n        value: \"US\",\n      },\n      {\n        field: \"states\",\n        operator: Operators.ContainsAny,\n        value: [\"KY\", \"TN\"],\n      },\n    ],\n  },\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid6.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src/enums\";\n\nexport const valid6Json: RuleType = {\n  conditions: [\n    {\n      or: [\n        {\n          field: \"Leverage\",\n          operator: Operators.Equals,\n          value: 1000,\n        },\n        {\n          field: \"Leverage\",\n          operator: Operators.Equals,\n          value: 500,\n        },\n        {\n          and: [\n            {\n              field: \"CountryIso\",\n              operator: Operators.Contains,\n              value: [\"GB\", \"FI\"],\n            },\n            {\n              field: \"Leverage\",\n              operator: Operators.LessThan,\n              value: 200,\n            },\n            {\n              field: \"Monetization\",\n              operator: Operators.Equals,\n              value: \"Real\",\n            },\n            {\n              or: [\n                {\n                  field: \"Category\",\n                  operator: Operators.GreaterThanOrEquals,\n                  value: 1000,\n                },\n                {\n                  field: \"Category\",\n                  operator: Operators.Equals,\n                  value: 22,\n                },\n                {\n                  or: [\n                    {\n                      field: \"Category\",\n                      operator: Operators.Equals,\n                      value: 11,\n                    },\n                    {\n                      field: \"Category\",\n                      operator: Operators.Equals,\n                      value: 12,\n                    },\n                    {\n                      and: [\n                        {\n                          field: \"Category\",\n                          operator: Operators.Equals,\n                          value: 122,\n                        },\n                        {\n                          field: \"IsUnder18\",\n                          operator: Operators.Equals,\n                          value: true,\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n      result: { value: 3 },\n    },\n    {\n      and: [\n        {\n          field: \"Category\",\n          operator: Operators.Equals,\n          value: \"Islamic\",\n        },\n      ],\n      result: { value: 4 },\n    },\n  ],\n  default: { value: 2 },\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid7.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src/enums\";\n\nexport const valid7Json: RuleType = {\n  conditions: [\n    {\n      none: [\n        {\n          and: [\n            {\n              field: \"CountryIso\",\n              operator: Operators.In,\n              value: [\"GB\", \"FI\"],\n            },\n            {\n              field: \"Leverage\",\n              operator: Operators.LessThan,\n              value: 200,\n            },\n            {\n              field: \"Monetization\",\n              operator: Operators.Equals,\n              value: \"Real\",\n            },\n          ],\n        },\n        {\n          field: \"Leverage\",\n          operator: Operators.GreaterThanOrEquals,\n          value: 1000,\n        },\n      ],\n      result: { value: 3 },\n    },\n    {\n      none: [\n        {\n          field: \"Category\",\n          operator: Operators.Equals,\n          value: \"Islamic\",\n        },\n      ],\n      result: { value: 4 },\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid8.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src/enums\";\n\nexport const valid8Json: RuleType = {\n  conditions: [\n    {\n      none: [\n        {\n          field: \"Leverage\",\n          operator: Operators.GreaterThanOrEquals,\n          value: 1000,\n        },\n        {\n          or: [\n            {\n              field: \"Type\",\n              operator: Operators.NotEquals,\n              value: \"Demo\",\n            },\n            {\n              field: \"OtherType\",\n              operator: Operators.NotIn,\n              value: [\"Live\", \"Fun\"],\n            },\n            {\n              and: [\n                {\n                  field: \"CountryIso\",\n                  operator: Operators.In,\n                  value: [\"GB\", \"FI\"],\n                },\n                {\n                  field: \"Leverage\",\n                  operator: Operators.LessThan,\n                  value: 200,\n                },\n                {\n                  field: \"Monetization\",\n                  operator: Operators.Equals,\n                  value: \"Real\",\n                },\n              ],\n            },\n          ],\n        },\n      ],\n      result: { value: 3 },\n    },\n    {\n      none: [\n        {\n          field: \"Category\",\n          operator: Operators.Equals,\n          value: \"Islamic\",\n        },\n      ],\n      result: { value: 4 },\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/core/test/rulesets/valid9.json.ts",
    "content": "import type { RuleType } from \"../../src\";\nimport { Operators } from \"../../src/enums\";\n\nexport const valid9Json: RuleType = {\n  conditions: [\n    {\n      or: [\n        {\n          and: [\n            {\n              field: \"country\",\n              operator: Operators.In,\n              value: [\"GB\", \"FI\"],\n            },\n            {\n              field: \"hasCoupon\",\n              operator: Operators.Equals,\n              value: true,\n            },\n            {\n              field: \"totalCheckoutPrice\",\n              operator: Operators.GreaterThanOrEquals,\n              value: 120.0,\n            },\n          ],\n        },\n        {\n          field: \"country\",\n          operator: Operators.Equals,\n          value: \"SE\",\n        },\n      ],\n      result: { value: 5 },\n    },\n    {\n      and: [\n        {\n          field: \"age\",\n          operator: Operators.GreaterThanOrEquals,\n          value: 18,\n        },\n        {\n          field: \"hasStudentCard\",\n          operator: Operators.Equals,\n          value: true,\n        },\n      ],\n      result: { value: 10 },\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/core/test/utils.spec.ts",
    "content": "import { it, expect, describe } from \"vitest\";\nimport {\n  isValidTime,\n  extractJsonPathExpressions,\n  convertTimeToMs,\n} from \"@root\";\n\ndescribe(\"isValidTime\", () => {\n  it(\"should return true for valid time strings\", () => {\n    expect(isValidTime(\"00:00\")).toBe(true);\n    expect(isValidTime(\"00:00\")).toBe(true);\n    expect(isValidTime(\"00:00\")).toBe(true);\n    expect(isValidTime(\"00:00\")).toBe(true);\n  });\n  it(\"should return true for valid time strings 2\", () => {\n    expect(convertTimeToMs(\"00:00\")).toBe(0);\n    expect(isValidTime(\"invalid\")).toBe(false);\n  });\n});\n\ndescribe(\"convertTimeToMs\", () => {\n  it(\"should convert valid time strings to milliseconds\", () => {\n    expect(convertTimeToMs(\"01:00\")).toBe(3600000);\n    expect(convertTimeToMs(\"00:00\")).toBe(0);\n    expect(convertTimeToMs(\"00:00\")).toBe(0);\n    expect(convertTimeToMs(\"00:00\")).toBe(0);\n    expect(convertTimeToMs(\"01:01:01\")).toBe(3661000);\n    expect(convertTimeToMs(\"00:01\")).toBe(60000);\n    expect(convertTimeToMs(\"00:01\")).toBe(60000);\n    expect(convertTimeToMs(\"00:01\")).toBe(60000);\n    expect(convertTimeToMs(\"01:01:01.001\")).toBe(3661001);\n  });\n\n  it(\"should throw an error for invalid time strings\", () => {\n    expect(() => convertTimeToMs(\"invalid\")).toThrowError(\n      \"Invalid time format\",\n    );\n    expect(() => convertTimeToMs(\"25:00\")).toThrowError(\"Invalid time format\");\n    expect(() => convertTimeToMs(\"00:61\")).toThrowError(\"Invalid time format\");\n    expect(() => convertTimeToMs(\"00:00:61\")).toThrowError(\n      \"Invalid time format\",\n    );\n    expect(() => convertTimeToMs(\"00:00:00:1000\")).toThrowError(\n      \"Invalid time format\",\n    );\n    expect(() => convertTimeToMs(\"00:00:00.2000\")).toThrowError(\n      \"Invalid time format\",\n    );\n  });\n});\n\ndescribe(\"extractJsonPathExpressions\", () => {\n  it(\"should extract simple JSONPath expressions\", () => {\n    const text = \"The value of $.foo.bar is $['foo']['bar']\";\n    const result = extractJsonPathExpressions(text);\n    expect(result).toEqual([\"$.foo.bar\", \"$['foo']['bar']\"]);\n  });\n\n  it(\"should handle nested structures\", () => {\n    const text = \"Nested: $.foo[0].bar[1].baz\";\n    const result = extractJsonPathExpressions(text);\n    expect(result).toEqual([\"$.foo[0].bar[1].baz\"]);\n  });\n\n  it(\"should handle parentheses in expressions\", () => {\n    const text = \"Expression with parentheses: $.foo.bar(1)\";\n    const result = extractJsonPathExpressions(text);\n    expect(result).toEqual([\"$.foo.bar(1)\"]);\n  });\n\n  it(\"should balance closing parentheses\", () => {\n    const text = \"Unbalanced parentheses: $.foo.bar(1))\";\n    const result = extractJsonPathExpressions(text);\n    expect(result).toEqual([\"$.foo.bar(1)\"]);\n  });\n\n  it(\"should balance closing brackets\", () => {\n    const text = \"Unbalanced brackets: $.foo[0]]\";\n    const result = extractJsonPathExpressions(text);\n    expect(result).toEqual([\"$.foo[0]\"]);\n  });\n\n  it(\"should handle multiple expressions in text\", () => {\n    const text = \"Multiple expressions: $.foo.bar, $.baz.qux\";\n    const result = extractJsonPathExpressions(text);\n    expect(result).toEqual([\"$.foo.bar\", \"$.baz.qux\"]);\n  });\n\n  it(\"should return an empty array if no expressions are found\", () => {\n    const text = \"No JSONPath expressions here.\";\n    const result = extractJsonPathExpressions(text);\n    expect(result).toEqual([]);\n  });\n\n  it(\"should handle text with both parentheses and brackets\", () => {\n    const text = \"Complex expression: $.foo[0].bar(1) and $.baz.qux[2]\";\n    const result = extractJsonPathExpressions(text);\n    expect(result).toEqual([\"$.foo[0].bar(1)\", \"$.baz.qux[2]\"]);\n  });\n});\n"
  },
  {
    "path": "packages/core/test/validator.spec.ts",
    "content": "import { it, expect, describe } from \"vitest\";\nimport { RuleEngine, Operators } from \"@root\";\nimport type { OperatorsType, Constraint, Condition } from \"@root\";\n// Assets\nimport { valid1Json } from \"./rulesets/valid1.json\";\nimport { valid3Json } from \"./rulesets/valid3.json\";\nimport { selfFieldsConstraintsJson } from \"./rulesets/self-fields-constraints.json\";\nimport { RegexRulesJson } from \"./rulesets/regex-rules.json\";\n\ndescribe(\"validator correctly\", () => {\n  it(\"identifies a bad operator\", () => {\n    expect(\n      RuleEngine.validate({\n        conditions: [\n          {\n            and: [\n              { field: \"name\", operator: \"*\" as OperatorsType, value: \"test\" },\n            ],\n          },\n        ],\n      }).isValid,\n    ).toEqual(false);\n  });\n\n  it(\"identifies an invalid field\", () => {\n    expect(\n      RuleEngine.validate({\n        conditions: [\n          {\n            and: [\n              {\n                field: true as unknown as string,\n                operator: Operators.Equals,\n                value: \"test\",\n              },\n            ],\n          },\n        ],\n      }).isValid,\n    ).toEqual(false);\n  });\n\n  it(\"identifies an invalid condition\", () => {\n    expect(\n      RuleEngine.validate({\n        conditions: [\n          {\n            and: [\n              {\n                field: \"foo\",\n                operator: Operators.Equals,\n                value: \"bar\",\n              },\n            ],\n            or: [],\n          },\n        ],\n      }).isValid,\n    ).toEqual(false);\n  });\n\n  it(\"identifies an invalid node\", () => {\n    expect(\n      RuleEngine.validate({\n        conditions: [\n          {\n            and: [\n              {\n                operator: Operators.Equals,\n                value: \"bar\",\n              } as Constraint,\n            ],\n          },\n        ],\n      }).isValid,\n    ).toEqual(false);\n  });\n\n  it(\"identifies an badly constructed condition\", () => {\n    expect(\n      RuleEngine.validate({\n        conditions: [\n          {\n            foo: [\n              {\n                field: \"foo\",\n                operator: Operators.Equals,\n                value: \"bar\",\n              },\n            ],\n          } as Condition,\n        ],\n      }).isValid,\n    ).toEqual(false);\n  });\n\n  it(\"identifies an empty rule\", () => {\n    const validation = RuleEngine.validate({ conditions: [] });\n\n    expect(validation.isValid).toEqual(false);\n    expect(validation.error?.message).toEqual(\n      \"The conditions property must contain at least one condition.\",\n    );\n  });\n\n  it(\"identifies invalid values for In/NotIn/ContainsAny operators\", () => {\n    expect(\n      RuleEngine.validate({\n        conditions: [\n          { and: [{ field: \"name\", operator: Operators.In, value: \"test\" }] },\n        ],\n      }).isValid,\n    ).toEqual(false);\n\n    expect(\n      RuleEngine.validate({\n        conditions: [\n          {\n            and: [{ field: \"name\", operator: Operators.NotIn, value: \"test\" }],\n          },\n        ],\n      }).isValid,\n    ).toEqual(false);\n\n    expect(\n      RuleEngine.validate({\n        conditions: [\n          {\n            and: [\n              { field: \"name\", operator: Operators.ContainsAny, value: \"test\" },\n            ],\n          },\n        ],\n      }).isValid,\n    ).toEqual(false);\n  });\n\n  it(\"validates a correct rule\", () => {\n    expect(\n      RuleEngine.validate({\n        conditions: [\n          {\n            and: [{ field: \"name\", operator: Operators.Equals, value: \"test\" }],\n          },\n        ],\n      }).isValid,\n    ).toEqual(true);\n  });\n\n  it(\"should return false for an invalid condition type\", () => {\n    expect(\n      RuleEngine.validate({\n        conditions: [\n          {\n            // @ts-ignore\n            and: [{ field: \"name\", operator: \"test\", value: \"test\" }],\n          },\n        ],\n      }).isValid,\n    ).toEqual(false);\n  });\n\n  it(\"validates a simple correct rule\", () => {\n    expect(RuleEngine.validate(valid1Json).isValid).toEqual(true);\n  });\n\n  it(\"validates a simple correct self rule\", () => {\n    expect(RuleEngine.validate(selfFieldsConstraintsJson).isValid).toEqual(\n      true,\n    );\n  });\n\n  it(\"validates a nested correct rule\", () => {\n    expect(RuleEngine.validate(valid3Json).isValid).toEqual(true);\n  });\n\n  it(\"validates a nested regex rules\", () => {\n    expect(RuleEngine.validate(RegexRulesJson).isValid).toEqual(true);\n  });\n});\n"
  },
  {
    "path": "packages/core/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"incremental\": false,\n    \"composite\": false,\n    \"types\": [\"node\"]\n  },\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "packages/core/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"lib\": [\"es2022\", \"esnext\"],\n    \"moduleDetection\": \"force\",\n    \"module\": \"preserve\",\n    \"strictNullChecks\": true,\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"allowJs\": true,\n    \"strict\": true,\n    \"noImplicitOverride\": true,\n    \"noUncheckedIndexedAccess\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"isolatedModules\": true,\n    \"verbatimModuleSyntax\": true,\n    \"skipLibCheck\": true,\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"noUnusedLocals\": false,\n    \"strictBindCallApply\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"incremental\": true,\n    \"sourceMap\": true,\n    \"baseUrl\": \"./\",\n    \"outDir\": \"dist\",\n    \"paths\": {\n      \"@root\": [\"./src\"],\n      \"@root/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"src/**/*\", \"test/**/*\", \"benchmarks/**/*\"],\n  \"exclude\": [\n    \"node_modules\",\n    \"dist\",\n    \"coverage\",\n    \".idea\",\n    \".vscode\",\n    \"**/*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "packages/core/tsup.config.ts",
    "content": "import { defineConfig } from \"tsup\";\nimport { resolve } from \"node:path\";\n\nexport default defineConfig((options) => ({\n  entry: [\"src/index.ts\"],\n  splitting: true,\n  format: [\"esm\", \"cjs\"],\n  treeshake: true,\n  watch: options.watch,\n  external: [],\n  target: \"esnext\",\n  sourcemap: true,\n  clean: true,\n  dts: true,\n  legacyOutput: true,\n  minify: !options.watch,\n  banner: {\n    js: `\n// -------------------------------------------------------------\n// UseStrict - Rule Engine\n// A Powerful Rule Engine for Node.js & Browser environments\n//\n// License: Proprietary - © UseStrict, All Rights Reserved\n//\n// Description:\n//   This library is part of the Ali Torki ecosystem, designed to\n//   handle complex business logic or dynamic decision-making\n//   scenarios. It can be seamlessly integrated into both Node.js\n//   backends and browser applications.\n//\n// Author: Ali Torki <ali_4286@live.com>\n// Docs:   https://rule-engine.usestrict.dev\n// -------------------------------------------------------------\n    `,\n  },\n  tsconfig: resolve(\n    __dirname,\n    options.watch ? \"tsconfig.json\" : \"tsconfig.build.json\",\n  ),\n}));\n"
  },
  {
    "path": "packages/core/vitest.config.ts",
    "content": "import { defineConfig } from \"vitest/config\";\nimport * as path from \"node:path\";\n\nexport default defineConfig({\n  test: {\n    alias: {\n      \"@root\": path.resolve(__dirname, \"./src\"),\n    },\n    server: {\n      sourcemap: \"inline\",\n    },\n    fileParallelism: true,\n    name: \"RuleEngine\",\n    benchmark: {\n      include: [\"./benchmarks/**/*.bench.ts\"],\n    },\n    typecheck: {\n      enabled: true,\n      checker: \"vue-tsc\",\n      ignoreSourceErrors: true,\n      tsconfig: path.resolve(process.cwd(), \"./tsconfig.json\"),\n    },\n    coverage: {\n      all: false,\n      clean: true,\n      provider: \"v8\",\n      cleanOnRerun: true,\n      reportOnFailure: true,\n      include: [\"**/src/**\"],\n      ignoreEmptyLines: true,\n      exclude: [\n        \"**/src/**/*.spec.ts\",\n        \"**/src/**/*.test.ts\",\n        \"**/src/**/*.bench.ts\",\n        \"**/src/**/*.d.ts\",\n        \"**/src/**/*.config.ts\",\n        \"**/src/**/index.ts\",\n      ],\n      processingConcurrency: 4,\n      experimentalAstAwareRemapping: true,\n      reporter: [\"clover\", \"json\", \"html\", \"html-spa\"],\n      reportsDirectory: path.resolve(__dirname, \"./coverage\"),\n    },\n    // dir: path.resolve(__dirname, \"./test\"),\n    cache: {\n      dir: path.resolve(__dirname, \"node_modules/.cache/vitest\"),\n    },\n    globals: true,\n    isolate: true,\n    update: true,\n    printConsoleTrace: true,\n    pool: \"vmForks\",\n    poolOptions: {\n      vmForks: {\n        singleFork: true,\n        memoryLimit: \"2GB\",\n        minForks: 1,\n        maxForks: 4,\n        isolate: true,\n      },\n    },\n  },\n});\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - \"packages/*\"\n  - \"apps/*\"\n\nignoredBuiltDependencies:\n  - esbuild\n\nonlyBuiltDependencies:\n  - simple-git-hooks\n"
  }
]