Source Tree Map

A guided tour of every package in src/main/groovy/nfneuro/, what each one owns, and how the packages relate to one another. The source tree and the compiled JAR share a common pattern: the filesystem path omits the plugin segment, but every class declares the full nfneuro.plugin.* package.

Package dependency graph

Directory ↔ Package Mapping

The root of the Groovy source tree is src/main/groovy/nfneuro/. Each sub-directory corresponds to one package segment after the implicit nfneuro.plugin prefix.

Directory Java package Top-level classes

nfneuro/plugin/

nfneuro.plugin

BidsPlugin, BidsExtension, BidsFactory, BidsObserver

nfneuro/channel/

nfneuro.plugin.channel

BidsChannelFactory, BidsHandler

nfneuro/channel/operations/

nfneuro.plugin.channel.operations

GroupTupleByOp, JoinByOp, CombineByOp

nfneuro/channel/operations/keys/

nfneuro.plugin.channel.operations.keys

KeyExtractor, CompositeKey

nfneuro/parser/

nfneuro.plugin.parser

BidsParser, LibBidsShWrapper, BidsValidator

nfneuro/config/

nfneuro.plugin.config

BidsConfigLoader, BidsConfigValidator, BidsConfigAnalyzer

nfneuro/grouping/

nfneuro.plugin.grouping

BaseSetHandler, PlainSetHandler, NamedSetHandler, SequentialSetHandler, MixedSetHandler

nfneuro/model/

nfneuro.plugin.model

BidsDataset, BidsEntity, BidsFile, BidsChannelData

nfneuro/util/

nfneuro.plugin.util

BidsLogger, SuffixMapper, BidsEntityUtils, BidsErrorHandler, BidsCsvParser

Package Responsibilities

nfneuro.plugin — Plugin Bootstrap

This package is the Nextflow integration layer. The four classes in it form the minimal surface that Nextflow’s pf4j plugin loader requires.

BidsPlugin

Extends nextflow.plugin.BasePlugin. Its sole job is to be discovered by pf4j via the plugin descriptor. It carries no domain logic.

BidsExtension

Extends PluginExtensionPoint and declares the public API: the @Factory method fromBIDS() and the three @Operator methods groupTupleBy(), joinBy(), and combineBy(). All factory and operator implementations are delegated to BidsChannelFactory and the *Op classes respectively.

BidsFactory

Implements TraceObserverFactory. Its create(Session) method instantiates a BidsObserver and registers it with the Nextflow trace system.

BidsObserver

Implements TraceObserver. Currently prints a startup banner on onFlowCreate and a completion message on onFlowComplete. This is the hook point for future workflow-level observability.

See Plugin Bootstrap for the pf4j lifecycle.

nfneuro.plugin.channel — Channel Assembly

Two classes orchestrate the entire Channel.fromBIDS() pipeline.

BidsChannelFactory

Receives the Session at construction and exposes fromBIDS(String bidsDir, String configPath, Map options). It runs pre-flight validation (directory existence, config file existence, optional libbids_sh path) and then constructs a BidsHandler using the fluent builder API.

BidsHandler

The stateful orchestrator. It holds the parsed configuration, the list of loopOverEntities, the suffixMapping, and the BidsParser. ignite(Session) creates the DataflowWriteChannel, registers an async igniter for DSL2 execution, and returns the channel. execute() calls parser.parseToDataset(), routes files through the appropriate set-handler subclass, applies cross-modal broadcasting, and emits items onto the channel. The channel is closed with Channel.STOP after all items are emitted.

nfneuro.plugin.channel.operations — Closure Operators

Each *Op class is a self-contained operator implementation.

GroupTupleByOp

Groups channel items by a closure-extracted key, accumulating items in a synchronized Map<Object, List> and emitting [key, [items]] tuples.

JoinByOp

Performs an inner join between two channels using independent key-extractor closures for left and right sides. Supports remainder and duplicate-handling options, emitting fused join payloads without keys.

CombineByOp

Emits the Cartesian product of left and right items within each key group as fused payloads (key omitted). BidsExtension provides three overloads to support a single shared extractor or separate left/right extractors.

nfneuro.plugin.channel.operations.keys — Key Infrastructure

KeyExtractor

Static utility that safely invokes a key-extractor closure on a channel item. It normalises List-valued keys by wrapping them in a CompositeKey so that Map lookups use value equality rather than reference equality.

CompositeKey

An @EqualsAndHashCode-annotated wrapper for multi-part keys (e.g., [subject, session]). Without this class, two distinct List instances with identical contents would hash differently in a HashMap.

nfneuro.plugin.parser — BIDS Parsing

BidsParser

Orchestrates the two-step parse: calls LibBidsShWrapper.parseBidsToTable() to obtain a TSV file, then passes it to BidsCsvParser (in util). Returns a fully populated BidsDataset.

LibBidsShWrapper

Bridges Groovy and the external libBIDS.sh bash library. Implements a priority-ordered discovery chain: plugin-embedded lib/libBIDS.sh first, then several relative paths, then system paths (/usr/local/bin, ~/.local/bin). Executes the script using an array-form command (bash -c 'set -euo pipefail && source …​') to prevent shell injection. See The libBIDS.sh Dependency for the full discovery order.

BidsValidator

A stub — BIDS validation via bids-validator is deferred to v1.1. The class exists but validate() logs a warning and returns immediately. Validation code in BidsChannelFactory is commented out.

nfneuro.plugin.config — Configuration Layer

BidsConfigLoader

Loads a YAML file with SnakeYAML, rejects the reserved key meta, and delegates structural validation to BidsConfigValidator.

BidsConfigValidator

Returns a ValidationResult containing lists of errors and warnings. Validates per-suffix configuration blocks and global keys such as loop_over.

BidsConfigAnalyzer

Inspects the loaded config map and returns a boolean analysis map (hasNamedSets, hasSequentialSets, hasMixedSets, hasPlainSets). BidsHandler uses this map to decide which BaseSetHandler subclasses to instantiate. Also extracts the loop_over entity list.

See Configuration for the YAML schema.

nfneuro.plugin.grouping — Set Handlers

BaseSetHandler

Abstract base providing the process(datasetRoot, bidsFiles, config, loopOverEntities, suffixMapping) template and the static getSetType() helper.

PlainSetHandler

Handles plain_set entries — one file per subject/session/run group per suffix.

NamedSetHandler

Handles named_set entries — multiple acquisition-direction variants collected under a config key (e.g., dwi_ap with ap and pa sub-keys).

SequentialSetHandler

Handles sequential_set entries — variable-length sequences such as multi-echo acquisitions, emitted as ordered lists.

MixedSetHandler

Handles mixed_set entries — heterogeneous datasets where the same suffix maps to multiple config keys via suffix_maps_to.

Multiple handler types can be active simultaneously for a single config file.

See BIDS Parsing for set-type semantics.

nfneuro.plugin.model — Domain Objects

BidsDataset

Root container for a parsed dataset. Loads dataset_description.json and participants.tsv on construction.

BidsFile

Represents one file entry from the libBIDS.sh TSV. Carries the path, suffix, associated extensions (.nii.gz, .json, .bval, .bvec, etc.), and a list of BidsEntity objects.

BidsEntity

A key-value pair (e.g., subject=sub-01). Holds the canonical long-form entity name and a SHORT_ENTITY_MAPPING that maps long names to BIDS prefix abbreviations.

BidsChannelData

The transient accumulator used by the set handlers before items are emitted. Stores a Map<String, Object> data (keyed by suffix), a list of raw file paths, and the bidsParentDir. toChannelTuple() converts the accumulator to the [groupingKey, enrichedData] tuple consumed by BidsHandler.

nfneuro.plugin.util — Cross-Cutting Utilities

BidsLogger

Thin Slf4j wrapper that prefixes every message with a bracketed context tag (e.g., [nf-bids-handler]).

SuffixMapper

Builds a Map<setType, Map<configKey, actualSuffix>> from suffix_maps_to entries. Used by the set handlers to resolve heterogeneous suffix configurations.

BidsEntityUtils

Static helpers for filtering BidsFile lists by entity values and checking entity matches.

BidsErrorHandler

Provides tryWithContext() for exception wrapping and createDetailedError() for multi-bullet diagnostic messages.

BidsCsvParser

Parses the TSV produced by libBIDSsh_parse_bids_to_table. The expected column order is derivatives,datatype,subject,template,session,cohort,sample,task,tracksys,acquisition,nucleus,volume,ceagent,tracer,stain,reconstruction,direction,run,modality,echo,flip,inversion,mtransfer,part,processing,hemisphere,space,split,recording,chunk,atlas,segmentation,scale,resolution,density,label,description,suffix,extension,path (tab-separated).

Dependency Direction

The dependency graph flows in one direction: higher-level packages depend on lower-level ones, never the reverse.

nfneuro.plugin
  └── nfneuro.plugin.channel
        ├── nfneuro.plugin.channel.operations
        │     └── nfneuro.plugin.channel.operations.keys
        ├── nfneuro.plugin.parser
        │     └── (uses nfneuro.plugin.util)
        ├── nfneuro.plugin.config
        │     └── (uses nfneuro.plugin.util)
        ├── nfneuro.plugin.grouping
        │     └── (uses nfneuro.plugin.model, nfneuro.plugin.util)
        └── nfneuro.plugin.model

nfneuro.plugin.util is the only package imported by all others; it has no internal dependencies.