Class FeatureIndexer

java.lang.Object
com.arc_e_tect.gradle.gherkin.indexing.FeatureIndexer

public class FeatureIndexer extends Object
Numbers Feature/Scenario titles directly in the source .feature files according to a configured IndexingMode.

A line whose existing number already matches the format mode would itself produce - a single integer for a Feature, or for a Scenario/Scenario Outline either a single integer (IndexingMode.SCENARIO) or <featureNumber>.<n> (IndexingMode.ALL, matched against that line's own feature's resolved number) - is left completely untouched: its number is "pinned". Every other numbered line (wrong format, or a leftover from a different mode, or IndexingMode.OFF itself never expecting a number at all) is stripped and, if mode numbers lines of that kind, assigned a fresh number one past the highest pinned number seen so far (or from 1, if none are pinned yet) - so a newly added file that happens to sort alphabetically before already-numbered files never bumps their numbers, and fresh numbers always read as a continuation of the existing sequence rather than backfilling a gap earlier in it. Passing forceRewrite = true instead ignores existing numbers entirely and renumbers everything from scratch, exactly as if every file were being numbered for the first time.

If two lines' existing numbers collide - e.g. two features or two scenarios within the same feature were each numbered independently on separate branches and now coexist after a merge - only the first one encountered keeps the pinned number; the other is treated as unnumbered and assigned a fresh one, so the collision is resolved instead of leaving both lines untouched.

Feature numbering (and, for IndexingMode.SCENARIO, Scenario numbering too) is additionally scoped by projectDirectories when given a non-empty list: each feature file is assigned to whichever directory in that list is its nearest enclosing ancestor, and every such group is numbered as its own independent 1-based sequence, completely unaware of every other group's numbers - so, in a multi-project Gradle build, passing every project's own directory numbers each project's features from 1 rather than continuing one build-wide count across all of them. An empty list (the default for the overloads that don't accept one) instead treats featureFiles as a single group, exactly as if every file belonged to the same project - today's only behaviour, and the one still used for a build-wide consolidated count. IndexingMode.ALL's Scenario numbering is unaffected either way: it's already scoped per Feature - strictly finer-grained than per-project - by resetting to 1 within every feature regardless of projectDirectories.

Never called with IndexingMode.CI: the caller skips invoking this class entirely for that mode, since CI means the feature files must be left completely untouched, not even to strip prior numbering the way IndexingMode.OFF does.

  • Constructor Details

    • FeatureIndexer

      public FeatureIndexer()
      Creates a new FeatureIndexer.
  • Method Details

    • reindex

      public void reindex(List<File> featureFiles, IndexingMode mode, boolean forceRewrite)
      Rewrites every file in featureFiles in place per mode and forceRewrite - see the class documentation for exactly what changes and what's left alone. Files are numbered in the order they appear in featureFiles - the caller is responsible for ordering that list the way numbers should be assigned. A file is only rewritten on disk when its content actually changes. Equivalent to reindex(List, IndexingMode, boolean, Runnable) with a callback that does nothing.
      Parameters:
      featureFiles - the feature files collected for this run, in the order to number them in
      mode - the indexing mode to apply
      forceRewrite - when true, ignores existing numbers and renumbers everything from scratch; when false, leaves already-correctly-numbered lines alone
    • reindex

      public void reindex(List<File> featureFiles, IndexingMode mode, boolean forceRewrite, Runnable onFileReindexed)
      Same as reindex(List, IndexingMode, boolean), additionally invoking onFileReindexed once for every file in featureFiles as it finishes being reindexed, so a caller can drive a progress indicator during what would otherwise be a single opaque, potentially long-running call.
      Parameters:
      featureFiles - the feature files collected for this run, in the order to number them in
      mode - the indexing mode to apply
      forceRewrite - when true, ignores existing numbers and renumbers everything from scratch; when false, leaves already-correctly-numbered lines alone
      onFileReindexed - invoked once per file in featureFiles, in order; never null
    • reindex

      public void reindex(List<File> featureFiles, IndexingMode mode, boolean forceRewrite, List<File> projectDirectories, Runnable onFileReindexed)
      Same as reindex(List, IndexingMode, boolean, Runnable), additionally scoping Feature/cross-file Scenario numbering to each of projectDirectories - see the class documentation for exactly how. Passing an empty list is equivalent to reindex(List, IndexingMode, boolean, Runnable).
      Parameters:
      featureFiles - the feature files collected for this run, in the order to number them in
      mode - the indexing mode to apply
      forceRewrite - when true, ignores existing numbers and renumbers everything from scratch; when false, leaves already-correctly-numbered lines alone
      projectDirectories - the directories numbering is independently scoped to, or empty for a single build-wide sequence
      onFileReindexed - invoked once per file in featureFiles, in order; never null