{"id":48904640,"url":"https://github.com/Mirkoddd/Sift","last_synced_at":"2026-05-02T20:00:35.636Z","repository":{"id":339419124,"uuid":"1160987146","full_name":"Mirkoddd/Sift","owner":"Mirkoddd","description":"A Fluent Regex Builder for Java","archived":false,"fork":false,"pushed_at":"2026-04-09T13:41:49.000Z","size":848,"stargazers_count":77,"open_issues_count":0,"forks_count":5,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-09T15:26:45.957Z","etag":null,"topics":["android-library","builder-pattern","fluent-api","hibernate-validator","jakarta-validation","java","java-library","regex","regex-builder","regex-dsl","regular-expressions","thread-safe","type-safe","validation"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Mirkoddd.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-18T15:52:59.000Z","updated_at":"2026-04-09T13:42:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Mirkoddd/Sift","commit_stats":null,"previous_names":["mirkoddd/sift"],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/Mirkoddd/Sift","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mirkoddd%2FSift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mirkoddd%2FSift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mirkoddd%2FSift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mirkoddd%2FSift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Mirkoddd","download_url":"https://codeload.github.com/Mirkoddd/Sift/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mirkoddd%2FSift/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32547651,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-02T19:18:06.202Z","status":"ssl_error","status_checked_at":"2026-05-02T19:16:21.335Z","response_time":132,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android-library","builder-pattern","fluent-api","hibernate-validator","jakarta-validation","java","java-library","regex","regex-builder","regex-dsl","regular-expressions","thread-safe","type-safe","validation"],"created_at":"2026-04-16T19:00:43.475Z","updated_at":"2026-05-02T20:00:35.629Z","avatar_url":"https://github.com/Mirkoddd.png","language":"Java","funding_links":[],"categories":["Projects"],"sub_categories":["Utility"],"readme":"# Sift\n\u003cimg referrerpolicy=\"no-referrer-when-downgrade\" src=\"https://static.scarf.sh/a.png?x-pxid=e931dfa9-02e9-406d-bde7-56f9e0000464\" alt=\"\"/\u003e[![Java 8+](https://img.shields.io/badge/Java-8+-blue.svg)](https://adoptium.net/)\n[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)\n\n[![Tests](https://github.com/mirkoddd/Sift/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/mirkoddd/Sift/actions)\n[![Coverage](https://raw.githubusercontent.com/mirkoddd/Sift/main/.github/badges/jacoco.svg)](https://github.com/mirkoddd/Sift/actions)\n\n**The Type-Safe Regex Builder for Java. If it compiles, it works.**\n\n---\n\n## The Problem\n\nYou've seen this before. Someone writes a regex, it works, and six months later nobody — including the author — can read it:\n\n```java\n// What does this even do?\nPattern p = Pattern.compile(\"^(?=[\\\\p{Lu}])[\\\\p{L}\\\\p{Nd}_]{3,15}+[0-9]?$\");\n```\n\nYou add a character class, break the balance of brackets, and find out at runtime. You copy a regex from Stack Overflow, miss an escape, and watch it fail silently in production. You duplicate the same validation pattern across DTOs and forget to update one of them.\n\n**There is a better way.**\n\n---\n\n## The Solution\n\nSift is a fluent DSL that turns regex construction into readable, self-documenting Java code. Its state machine enforces grammatical correctness at **compile time** — if your pattern compiles, it is structurally valid.\n\n```java\n// The same pattern, written with Sift:\nString regex = Sift.fromStart()\n                .exactly(1).upperCaseLettersUnicode()   // Must start with an uppercase letter\n                .then()\n                .between(3, 15).wordCharactersUnicode().withoutBacktracking() // ReDoS-safe\n                .then()\n                .optional().digits()                    // May end with a digit\n                .andNothingElse()\n                .shake();\n\n// Result: ^[\\p{Lu}][\\p{L}\\p{Nd}_]{3,15}+[0-9]?$\n```\n\nYour IDE guides every step. Wrong transitions simply do not exist as methods.\n\n---\n\n## Installation\n[![sift-core](https://img.shields.io/maven-central/v/com.mirkoddd/sift-core?label=sift-core)](https://central.sonatype.com/artifact/com.mirkoddd/sift-core)\n[![sift-annotations](https://img.shields.io/maven-central/v/com.mirkoddd/sift-annotations?label=sift-annotations)](https://central.sonatype.com/artifact/com.mirkoddd/sift-annotations)\n\n[![sift-engine-re2j](https://img.shields.io/maven-central/v/com.mirkoddd/sift-engine-re2j?label=sift-engine-re2j)](https://central.sonatype.com/artifact/com.mirkoddd/sift-engine-re2j)\n[![sift-engine-graalvm](https://img.shields.io/maven-central/v/com.mirkoddd/sift-engine-graalvm?label=sift-engine-graalvm)](https://central.sonatype.com/artifact/com.mirkoddd/sift-engine-graalvm)\n\n**Gradle:**\n```groovy\n// Core engine — zero external dependencies\nimplementation 'com.mirkoddd:sift-core:\u003clatest\u003e'\n\n// Optional: Jakarta Validation / Hibernate Validator integration\nimplementation 'com.mirkoddd:sift-annotations:\u003clatest\u003e'\n\n\n// Optional: Engine RE2J\nimplementation 'com.mirkoddd:sift-engine-re2j:\u003clatest\u003e'\n\n\n// Optional: Engine GraalVM\nimplementation 'com.mirkoddd:sift-engine-graalvm:\u003clatest\u003e'\n```\n\n**Maven:**\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.mirkoddd\u003c/groupId\u003e\n    \u003cartifactId\u003esift-core\u003c/artifactId\u003e\n    \u003cversion\u003elatest\u003c/version\u003e\n\u003c/dependency\u003e\n\n\u003c!-- Optional: Jakarta Validation / Hibernate Validator integration --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.mirkoddd\u003c/groupId\u003e\n    \u003cartifactId\u003esift-annotations\u003c/artifactId\u003e\n    \u003cversion\u003elatest\u003c/version\u003e\n\u003c/dependency\u003e\n\n\n\u003c!-- Optional: Engine GraalVM --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.mirkoddd\u003c/groupId\u003e\n    \u003cartifactId\u003esift-engine-graalvm\u003c/artifactId\u003e\n    \u003cversion\u003elatest\u003c/version\u003e\n\u003c/dependency\u003e\n\n\n\u003c!-- Optional: Engine RE2J --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.mirkoddd\u003c/groupId\u003e\n    \u003cartifactId\u003esift-engine-re2j\u003c/artifactId\u003e\n    \u003cversion\u003elatest\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\u003e Sift targets **Java 8 bytecode** for maximum compatibility — including legacy Spring Boot 2.x and Android.\n\n---\n\n## Core Concepts\n\n### Entry Points\n\n| Method | Generates | Use when |\n|---|---|---|\n| `Sift.fromStart()` | `^...` | Validating from the start of a line (affected by `MULTILINE` flag) |\n| `Sift.fromAbsoluteStart()` | `\\A...` | Validating from the absolute start of the string (CRLF/Multi-Line safe) |\n| `Sift.fromAnywhere()` | `...` | Building reusable fragments or searching within text |\n| `Sift.fromWordBoundary()` | `\\b...` | Matching whole words |\n| `Sift.fromPreviousMatchEnd()` | `\\G...` | Iterative parsing |\n| `Sift.filteringWith(flag)` | `(?i)...` | Global flags (case-insensitive, multiline, dotall) |\n\n### Terminal Methods\n\n| Method | Effect |\n|---|---|\n| `.shake()` | Returns the raw regex `String` |\n| `.sieve()` | Compiles with the default JDK engine → `SiftCompiledPattern` |\n| `.sieveWith(engine)` | Compiles with a custom engine → `SiftCompiledPattern` |\n| `.andNothingElse()` | Appends `$` and seals the pattern — affected by `MULTILINE` flag and trailing newlines |\n| `.andNothingElseAbsolutely()` | Appends `\\z` — absolute end of string, completely immune to multi-line and CRLF injection bypasses |\n| `.andNothingElseBeforeFinalNewline()` | Appends `\\Z` — end of string, or just before a final `\\n` |\n---\n\n## Examples\n\n### 1. Modular Composition — The LEGO Brick Approach\n\nThe real power of Sift is the ability to name your building blocks and compose them. Every `Sift.fromAnywhere()` call returns a reusable `SiftPattern\u003cFragment\u003e` that can be embedded anywhere without carrying unwanted anchors.\n\n```java\n// Define named building blocks\nSiftPattern\u003cFragment\u003e year     = Sift.fromAnywhere().exactly(4).digits();\nSiftPattern\u003cFragment\u003e month    = Sift.fromAnywhere().exactly(2).digits();\nSiftPattern\u003cFragment\u003e day      = Sift.fromAnywhere().exactly(2).digits();\nSiftPattern\u003cFragment\u003e dash     = Sift.fromAnywhere().character('-');\n\n// Compose them into a date block\nSiftPattern\u003cFragment\u003e dateBlock = year.followedBy(dash, month, dash, day);\n\n// Embed inside a larger pattern\nString logRegex = Sift.fromStart()\n        .of(dateBlock)\n        .followedBy(' ')\n        .then().oneOrMore().anyCharacter()\n        .andNothingElse()\n        .shake();\n\n// Result: ^[0-9]{4}-[0-9]{2}-[0-9]{2} .+$\n```\n\n\u003e **Root vs Fragment:** Patterns built with `fromStart()` or `fromAbsoluteStart()`, or closed with `andNothingElse()`, `andNothingElseAbsolutely()`, or `andNothingElseBeforeFinalNewline()` become `SiftPattern\u003cRoot\u003e` — they are sealed and cannot be embedded.\n---\n\n### 2. Data Extraction — Beyond Pattern Matching\n\nSift patterns are not just validators. They are fully equipped extraction tools.\n\n```java\n// Define a structured pattern with named groups\nNamedCapture yearGroup  = SiftPatterns.capture(\"year\",  Sift.exactly(4).digits());\nNamedCapture monthGroup = SiftPatterns.capture(\"month\", Sift.exactly(2).digits());\nNamedCapture dayGroup   = SiftPatterns.capture(\"day\",   Sift.exactly(2).digits());\n\nSiftPattern\u003c?\u003e datePattern = Sift.fromStart()\n        .namedCapture(yearGroup)\n        .followedBy('-')\n        .then().namedCapture(monthGroup)\n        .followedBy('-')\n        .then().namedCapture(dayGroup)\n        .andNothingElse();\n\n// Extract structured data directly — no Matcher boilerplate\nMap\u003cString, String\u003e fields = datePattern.extractGroups(\"2026-03-13\");\n// → { \"year\": \"2026\", \"month\": \"03\", \"day\": \"13\" }\n\n// Extract all matches from a larger text\nList\u003cString\u003e prices = Sift.fromAnywhere()\n        .oneOrMore().digits()\n        .sieve()\n        .extractAll(\"Order: 3 items at 25 and 40 euros\");\n// → [\"3\", \"25\", \"40\"]\n\n// Stream results lazily for large inputs\nSift.fromAnywhere().oneOrMore().lettersUnicode()\n    .streamMatches(largeText)\n    .filter(word -\u003e word.length() \u003e 5)\n    .forEach(System.out::println);\n```\n\n**Full extraction API:**\n\n| Method | Returns | Description |\n|---|---|---|\n| `containsMatchIn(input)` | `boolean` | Is there at least one match? |\n| `matchesEntire(input)` | `boolean` | Does the entire string match? |\n| `extractFirst(input)` | `Optional\u003cString\u003e` | First match, or empty |\n| `extractAll(input)` | `List\u003cString\u003e` | All matches |\n| `extractGroups(input)` | `Map\u003cString, String\u003e` | Named groups from first match |\n| `extractAllGroups(input)` | `List\u003cMap\u003cString, String\u003e\u003e` | Named groups from all matches |\n| `replaceFirst(input, replacement)` | `String` | Replace first match |\n| `replaceAll(input, replacement)` | `String` | Replace all matches |\n| `splitBy(input)` | `List\u003cString\u003e` | Split around matches |\n| `streamMatches(input)` | `Stream\u003cString\u003e` | Lazy stream of all matches |\n\n---\n\n### 3. Jakarta Validation Integration\n\nStop duplicating regex logic across your DTOs. Define a rule once, reuse it everywhere with `@SiftMatch`.\n\n```java\n// 1. Define a reusable rule\npublic class PromoCodeRule implements SiftRegexProvider {\n    @Override\n    public String getRegex() {\n        return Sift.fromStart()\n                .atLeast(4).letters()\n                .then()\n                .exactly(3).digits()\n                .andNothingElse()\n                .shake();\n    }\n}\n\n// 2. Apply it declaratively — pattern is compiled once at bootstrap\npublic record ApplyPromoRequest(\n        @SiftMatch(\n                value   = PromoCodeRule.class,\n                flags   = { SiftMatchFlag.CASE_INSENSITIVE },\n                message = \"Invalid promo code format\"\n        )\n        String promoCode\n) {}\n```\n\n---\n\n### 4. ReDoS Mitigation\n\nSift makes performance-safe patterns easy to express without memorizing obscure syntax.\n\n```java\n// Possessive quantifier — prevents catastrophic backtracking\nSift.fromAnywhere()\n    .oneOrMore().wordCharacters().withoutBacktracking(); // generates \\w++\n\n// Atomic group — locks a sub-pattern once matched\nSiftPattern\u003cFragment\u003e safe = Sift.fromAnywhere()\n        .oneOrMore().digits()\n        .preventBacktracking(); // wraps in (?\u003e...)\n\n// Lazy quantifier — matches as few characters as possible\nSift.fromAnywhere()\n    .oneOrMore().anyCharacter().asFewAsPossible(); // generates .+?\n```\n---\n### 5. Alternative Regex Engines\n\nBy default, Sift compiles patterns using the standard `java.util.regex` engine via `.sieve()`.\nFor use cases where the JDK engine is not suitable — such as environments requiring\nlinear-time guarantees or GraalVM native images — Sift exposes a `SiftEngine` SPI that\naccepts any compatible backend.\n```java\n// Default — uses java.util.regex internally\nSiftCompiledPattern pattern = Sift.fromAnywhere()\n                .oneOrMore().digits()\n                .sieve();\n\n// Custom engine — e.g. RE2J for linear-time, ReDoS-immune matching\nSiftCompiledPattern pattern = Sift.fromAnywhere()\n        .oneOrMore().digits()\n        .sieveWith(Re2jEngine.INSTANCE); // sift-engine-re2j module\n```\n\nSift tracks the advanced features used during pattern construction as a `Set\u003cRegexFeature\u003e`\nand passes it to the engine at compile time. If an engine doesn't support a requested\nfeature — for example, RE2J does not support lookarounds or backreferences — it throws\n`UnsupportedOperationException` immediately, before any input is processed.\n\nAvailable engine modules:\n- `sift-core` — includes `JdkEngine` (default, zero dependencies)\n- `sift-engine-re2j` — RE2J backend, guarantees linear-time O(n) matching, immune to ReDoS\n- `sift-engine-graalvm` — GraalVM TRegex backend, AOT-ready for native images\n\n---\n\n### 6. Lookarounds — Zero-Width Assertions\n\nLookarounds let you match based on what surrounds a position without consuming those characters. Sift exposes them as readable methods directly on `Connector`, so they flow naturally in the chain.\n```java\n// Positive lookahead — match \"file\" only if followed by \".pdf\"\nSiftPattern\u003cFragment\u003e pdfFile = Sift.fromAnywhere()\n                .oneOrMore().wordCharacters()\n                .mustBeFollowedBy(SiftPatterns.literal(\".pdf\"));\n\n// Negative lookahead — match a number NOT followed by \"%\"\nSiftPattern\u003cFragment\u003e absoluteValue = Sift.fromAnywhere()\n        .oneOrMore().digits()\n        .notFollowedBy(SiftPatterns.literal(\"%\"));\n\n// Positive lookbehind — match digits only if preceded by \"$\"\nSiftPattern\u003cFragment\u003e dollarAmount = Sift.fromAnywhere()\n        .oneOrMore().digits()\n        .mustBePrecededBy(SiftPatterns.literal(\"$\"));\n\n// Negative lookbehind — match \"port\" NOT preceded by \"pass\"\nSiftPattern\u003cFragment\u003e networkPort = Sift.fromAnywhere()\n        .of(SiftPatterns.literal(\"port\"))\n        .notPrecededBy(SiftPatterns.literal(\"pass\"));\n```\n\nAll four lookaround types are available both on `Connector` — for inline chaining — and as standalone factories in `SiftPatterns` for use in composition with `followedByAssertion()` and `precededByAssertion()`.\n\n---\n\n### 7. Ready-Made Patterns — SiftCatalog\n\n`SiftCatalog` provides a curated set of production-ready, ReDoS-safe patterns for common formats. All patterns are `Fragment`-typed — they compose cleanly with your own Sift chains.\n\n```java\n// Use standalone\nboolean valid = SiftCatalog.email().matchesEntire(\"user@example.com\");\n\n// Or embed inside a larger pattern\nString regex = Sift.fromStart()\n        .of(SiftCatalog.uuid())\n        .followedBy('/')\n        .then().of(SiftCatalog.isoDate())\n        .andNothingElse()\n        .shake();\n```\n\nAvailable patterns: `uuid()`, `ipv4()`, `macAddress()`, `email()`, `webUrl()`, `isoDate()`,\n`iban()`, `jwt()`, `creditCard()`, `base64()`, `base64Url()`.\n\n---\n\n### 8. Recursive \u0026 Nested Structures\n\nParse arbitrarily deep balanced structures with `SiftPatterns.nesting()`.\n\n```java\n// Match nested parentheses: ((a)(b))\nSiftPattern\u003cFragment\u003e nested = SiftPatterns.nesting(5)\n                .using(Delimiter.PARENTHESES)\n                .containing(Sift.fromAnywhere().oneOrMore().lettersUnicode());\n\nnested.containsMatchIn(\"((hello)(world))\"); // true\n```\n\n---\n\n### 9. Conditional Patterns\n\nSift exposes regex conditional logic — `if/then/else` branches — as a fully type-safe fluent API via `SiftPatterns`.\n```java\n// Match a price: if preceded by \"USD\" consume digits only,\n// otherwise consume digits followed by a currency symbol\nSiftPattern\u003cFragment\u003e price = SiftPatterns\n                .ifPrecededBy(SiftPatterns.literal(\"USD\"))\n                .thenUse(Sift.fromAnywhere().oneOrMore().digits())\n                .otherwiseUse(\n                        Sift.fromAnywhere().oneOrMore().digits()\n                                .followedBy(Sift.fromAnywhere().character('€'))\n                );\n\n// Else-if chaining is also supported\nSiftPattern\u003cFragment\u003e format = SiftPatterns\n        .ifFollowedBy(SiftPatterns.literal(\"px\"))\n        .thenUse(Sift.fromAnywhere().oneOrMore().digits())\n        .otherwiseIfFollowedBy(SiftPatterns.literal(\"%\"))\n        .thenUse(Sift.fromAnywhere().between(1, 3).digits())\n        .otherwiseNothing(); // No else branch — engine moves forward silently\n```\n\nThe state machine enforces the correct declaration order at compile time: `ifXxx` → `thenUse` → `otherwiseUse` / `otherwiseIfFollowedBy` / `otherwiseNothing`. An incomplete conditional is not expressible.\n\n---\n\n### 10. Pattern Explanation\n\nSift can translate any pattern into a human-readable ASCII tree — useful for debugging,\ndocumentation, and onboarding. The explainer supports multiple languages via i18n.\n```java\nSiftPattern pattern = Sift.fromStart()\n        .oneOrMore().digits()\n        .andNothingElse();\n\n// English (default)\nSystem.out.println(pattern.explain());\n\n// Italian\nSystem.out.println(pattern.explain(Locale.ITALIAN));\n\n// Spanish\nSystem.out.println(pattern.explain(new Locale(\"es\")));\n```\n\nOutput (English):\n```\n┌─ Starts at the beginning of the line\n├─ a digit one or more times\n└─ Ends at the end of the line\n```\n\n`explain()` is available directly on every `SiftPattern` and delegates to `SiftExplainer`,\nwhich can also be called standalone for more control over the locale resolution.\n\n---\n\n## Why Sift?\n\n| | Raw Java Regex | Sift |\n|---|---|---|\n| Syntax errors | Discovered at runtime | Impossible to express |\n| Readability | Cryptic symbols | Self-documenting method names |\n| Reusability | Copy-paste | Named `SiftPattern` fragments |\n| Thread safety | Manual | Guaranteed, all patterns are immutable |\n| ReDoS protection | Requires expert knowledge | Built-in API |\n| Jakarta Validation | Manual `@Pattern` duplication | `@SiftMatch` + `SiftRegexProvider` |\n| Regex engine | JDK only | Pluggable (JDK, RE2J, GraalVM, etc...) |\n| Dependencies | — | Zero (sift-core) |\n| Human-readable explanation | Not possible | `pattern.explain()` with i18n support |\n| CRLF / Header Injection | Manual anchor management (`\\z`) | Native API (`andNothingElseAbsolutely()`) |\n---\n\n## Going Further\n\n- **[Sift Cookbook](COOKBOOK.md)** — Advanced recipes: TSV log parsing, UUID validation, lookarounds, data extraction with named captures, conditional patterns, and more.\n- **[Javadoc — sift-core](https://javadoc.io/doc/com.mirkoddd/sift-core)**\n- **[Javadoc — sift-annotations](https://javadoc.io/doc/com.mirkoddd/sift-annotations)**\n- **[Javadoc — sift-engine-re2j](https://javadoc.io/doc/com.mirkoddd/sift-engine-re2j)**\n- **[Javadoc — sift-engine-graalvm](https://javadoc.io/doc/com.mirkoddd/sift-engine-graalvm)**\n- **[Changelog](CHANGELOG.md)**\n- **[Contributing](CONTRIBUTING.md)**\n\n## Under the Hood\n\nCurious how Sift converts a fluent API chain into a compiled regex without performance overhead? Or want to know how the Type-State pattern catches errors at compile-time?\n\nCheck out the [Sift Architecture](ARCHITECTURE.md) to see the magic behind the AST (Abstract Syntax Tree) and learn how easy it is to add your own DSL methods or execution engines.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMirkoddd%2FSift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMirkoddd%2FSift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMirkoddd%2FSift/lists"}