Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 0 additions & 37 deletions .github/agents/documentation.agent.md

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ jobs:
keep_files: true
- name: SonarQube Scan
run: |
mvn -B -f pom.xml package -Dmaven.test.skip=true org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.java.source=24 -Dsonar.java.target=24 -Dsonar.token=$SONAR_TOKEN -Dsonar.host.url=https://sonarcloud.io/ -Dsonar.organization=$SONAR_ORGANIZATION -Dorganization=$SONAR_ORGANIZATION -Dsonar.projectKey=dan323_functional-by-annotations
mvn -B -f pom.xml package -Dmaven.test.skip=true org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.java.source=24 -Dsonar.java.target=24 -Dsonar.token=$SONAR_TOKEN -Dsonar.host.url=https://sonarcloud.io/ -Dsonar.organization=$SONAR_ORGANIZATION -Dorganization=$SONAR_ORGANIZATION -Dsonar.projectKey=functional-by-annotations
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_ORGANIZATION: ${{ secrets.SONAR_ORGANIZATION }}
Expand Down
80 changes: 80 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Build Commands

```bash
# Build all modules (skip tests)
mvn install -DskipTests

# Run all tests
mvn test -P test

# Run tests for a single module
mvn test -P test -pl example-functional
mvn test -P test -pl functional-definitions/functional-compiler

# Run a single test class
mvn test -P test -pl example-functional -Dtest=FiniteListTest

# Generate coverage report (JaCoCo)
mvn verify -P jacoco

# Mutation testing
mvn test pitest:mutationCoverage -pl functional-definitions/functional-compiler

# SonarQube analysis
mvn sonar:sonar
```

The `test` Maven profile is required for running tests — it configures JaCoCo and adds the necessary `--add-exports` JVM arg for the JPMS module system.

## Module Structure

Three top-level Maven modules:

- **`functional-definitions/annotation-definitions`** — Pure API layer. Defines the 9 annotations (`@Functor`, `@Applicative`, `@Monad`, `@Foldable`, `@Traversal`, `@Alternative`, `@Semigroup`, `@Monoid`, `@Ring`), the marker interfaces (`Functional<F>`, `Algebraic`, `ClassAware<F>`), and the structural interfaces (`IFunctor`, `IApplicative`, `IMonad`, `IFoldable`, `ITraversal`, `IAlternative`, `ISemigroup`, `IMonoid`, `IRing`). No dependencies.

- **`functional-definitions/functional-compiler`** — Compile-time annotation processor. `FunctionalCompiler` (extends `AbstractProcessor`) validates that annotated classes implement the required interface and provide the minimal set of required methods. It does not generate new source files — it validates only. SPI-registered in `module-info.java`.

- **`example-functional`** — Example implementations of functional data structures: `FiniteList`, `InfiniteList`, `Identity`, `Either`, `Optional`, `Continuation`, `Reader`, `Parser`, `Pair`, `Tree`, `Writer`, `State`, SQL types, and list zipper. The annotation processor is wired in via `annotationProcessorPaths` in its pom.xml.

- **`jacoco-functional`** — Coverage aggregator only (pom packaging, no source). Activated via `-P jacoco`.

Dependency direction: `annotation-definitions` ← `functional-compiler` ← `example-functional`.

## Architecture: How the Annotation Processor Works

The goal is to let users annotate a class (e.g., `@Monad`) and get a compile-time error if they forgot to implement the required minimal method set (e.g., `pure` + `flatMap`).

**Processing pipeline in `FunctionalCompiler`:**
1. For each annotated type, collect which `Functional`/`Algebraic` interfaces it directly implements via `CompilerUtils.getDirectFunctionalInterfaces()`.
2. `CompilerFactory.from()` maps each interface to a concrete `Compiler<A>` instance containing a structure-specific signature checker.
3. Each `Compiler.process()` walks the class hierarchy and verifies the required method signatures are present. Errors are emitted via `Messager`.

**Required methods per structure:**
- `@Functor` / `IFunctor` → `map`
- `@Applicative` / `IApplicative` → `pure` + (`fapply` or `liftA2`)
- `@Monad` / `IMonad` → `pure` + `flatMap`
- `@Foldable` / `IFoldable` → one of: `fold`, `foldMap`, `foldr`
- `@Traversal` / `ITraversal` → `traverse` or `sequenceA`
- `@Alternative` / `IAlternative` → `IApplicative` methods + `empty` + `disjunction`
- `@Semigroup` / `ISemigroup` → `op`
- `@Monoid` / `IMonoid` → `op` + `unit`
- `@Ring` / `IRing` → addition + multiplication operations

**Signature checking internals** live in `functional-compiler/src/main/java/.../compiler/internal/`: `CompilerFactory`, `Compiler`, `StructureSignatures`, and `NecessaryMethods` (conjunctive/disjunctive/empty states).

## JPMS (Java Module System)

All three source modules declare `module-info.java`. When writing tests in `example-functional` that need access to compiler-internal types, the `test` profile adds:
```
--add-exports=functional.data/com.dan323.mock=functional.compiler
```

The `functional.compiler` module uses `provides javax.annotation.processing.Processor with FunctionalCompiler` in its module-info to register the SPI.

## Java Version

The project targets Java 17 minimum and is tested on 17, 21, and 24 in CI. Profile-based compiler configuration in the root `pom.xml` handles version-specific settings. Use `--release 17` semantics when writing new code.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
[![GitHub forks](https://img.shields.io/github/forks/dan323/functional-by-annotations)](https://github.com/dan323/functional-by-annotations/network)
[![Last Commit](https://img.shields.io/github/last-commit/dan323/functional-by-annotations)](https://github.com/dan323/functional-by-annotations/commits)

[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=dan323_functional-by-annotations&metric=alert_status)](https://sonarcloud.io/dashboard?id=dan323_functional-by-annotations)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=dan323_functional-by-annotations&metric=coverage)](https://sonarcloud.io/dashboard?id=dan323_functional-by-annotations)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=dan323_functional-by-annotations&metric=bugs)](https://sonarcloud.io/dashboard?id=dan323_functional-by-annotations)
[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=dan323_functional-by-annotations&metric=code_smells)](https://sonarcloud.io/dashboard?id=dan323_functional-by-annotations)
[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=functional-by-annotations&metric=alert_status)](https://sonarcloud.io/dashboard?id=dan323_functional-by-annotations)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=functional-by-annotations&metric=coverage)](https://sonarcloud.io/dashboard?id=dan323_functional-by-annotations)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=functional-by-annotations&metric=bugs)](https://sonarcloud.io/dashboard?id=dan323_functional-by-annotations)
[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=functional-by-annotations&metric=code_smells)](https://sonarcloud.io/dashboard?id=dan323_functional-by-annotations)

> Bring functional programming concepts to Java through annotations and compile-time code generation

Expand Down
8 changes: 4 additions & 4 deletions docs/EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public class FiniteListFunctional implements
Function<A, B> f) {
return list.head().maybe(
h -> FiniteList.cons(f.apply(h), map(list.tail(), f)),
FiniteList.nil()
List.nil()
);
}

Expand All @@ -155,7 +155,7 @@ public class FiniteListFunctional implements
FiniteList<A> list) {
return list.head().maybe(
h -> concat(f.apply(h), flatMap(f, list.tail())),
FiniteList.nil()
List.nil()
);
}

Expand All @@ -175,7 +175,7 @@ public class FiniteListFunctional implements
IApplicative<K> app,
Function<A, K> f,
FiniteList<A> list) {
K empty = ApplicativeUtil.pure(app, FiniteList.nil());
K empty = ApplicativeUtil.pure(app, List.nil());
return foldr(
(x, y) -> ApplicativeUtil.liftA2(app, FiniteList::cons, f.apply(x), y),
empty,
Expand All @@ -185,7 +185,7 @@ public class FiniteListFunctional implements

// Alternative
public static <A> FiniteList<A> empty() {
return FiniteList.nil();
return List.nil();
}

public static <A> FiniteList<A> disjunction(
Expand Down
2 changes: 1 addition & 1 deletion docs/FUNCTIONAL_STRUCTURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public class ListTraversal implements ITraversal<FiniteList<?>> {
IApplicative<K> app,
Function<A, K> f,
FiniteList<A> lst) {
K empty = ApplicativeUtil.pure(app, FiniteList.nil());
K empty = ApplicativeUtil.pure(app, List.nil());
return foldr((x, y) ->
ApplicativeUtil.liftA2(app, FiniteList::cons, f.apply(x), y),
empty, lst);
Expand Down
2 changes: 1 addition & 1 deletion docs/PARSER.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ var result = numbers.apply("1,2,3");
// Returns: Either.right(Pair(FiniteList.of(1, 2, 3), ""))

var empty = numbers.apply("abc");
// Returns: Either.right(Pair(FiniteList.nil(), "abc")) // zero values is ok
// Returns: Either.right(Pair(List.nil(), "abc")) // zero values is ok
```

### Disjunction/Alternative
Expand Down
16 changes: 8 additions & 8 deletions docs/PIPELINE.md
Original file line number Diff line number Diff line change
Expand Up @@ -410,14 +410,14 @@ Recommended branch protection rules for `master`:

### Current Targets

| Metric | Target | Current | Status |
|--------|--------|---------|--------|
| Line Coverage | ≥85% | Check [Reports](https://dan323.github.io/functional-by-annotations/) | - |
| Mutation Coverage | ≥85% | Check [Reports](https://dan323.github.io/functional-by-annotations/pit-reports/) | - |
| SonarCloud Quality Gate | Pass | Check [SonarCloud](https://sonarcloud.io/dashboard?id=dan323_functional-by-annotations) | - |
| Bugs | 0 | - | - |
| Vulnerabilities | 0 | - | - |
| Code Smells | A Rating | - | - |
| Metric | Target | Current | Status |
|-------------------------|----------|----------------------------------------------------------------------------------|--------|
| Line Coverage | ≥85% | Check [Reports](https://dan323.github.io/functional-by-annotations/) | - |
| Mutation Coverage | ≥85% | Check [Reports](https://dan323.github.io/functional-by-annotations/pit-reports/) | - |
| SonarCloud Quality Gate | Pass | Check [SonarCloud](https://sonarcloud.io/dashboard?id=functional-by-annotations) | - |
| Bugs | 0 | - | - |
| Vulnerabilities | 0 | - | - |
| Code Smells | A Rating | - | - |

### Historical Trends

Expand Down
Loading
Loading