Class: Ecoportal::API::GraphQL::Model::Template::CommandNormalizer

Inherits:
Object
  • Object
show all
Defined in:
lib/ecoportal/api/graphql/model/template/command_normalizer.rb

Overview

Normalises an ordered batch of built WorkflowCommand hashes ([{ commandKey => { ...input } }, ...]) so that batches produced by DIFFERENT

emitters -- each of which mints its own placeholder/id tokens (`Builder

TemplateBuilder's ph_stg_1, Diff::CommandSynthesizer's ph_stg_0, CommandSynthesis's ph_stg_1`, a self-version replay's real server ids, the downstream writers' caller-chosen tokens) -- can be compared for STRUCTURAL equivalence.

Two normalisations, both pure (no mutation of the input):

1. REFERENCE-TOKEN POSITIONING. Every value carried under a key this class
 recognises as an id/placeholder REFERENCE (see `REFERENCE_KEYS`) is replaced
 by a positional token `"ph_<n>"`, assigned in FIRST-APPEARANCE order across
 the whole ordered batch (scanning left to right, top to bottom, depth-first
 within each command's own Hash). The SAME source value always maps to the
 SAME token wherever it recurs (so a mint-then-reference pair, e.g. `addStage`'s
 `placeholderId` and a later `addStageSection`'s `stageId`, stays linked). Only
 the KEY decides whether a String is a reference -- literal content
 (`label`/`name`/`value`/`script`/`url`/...) is never touched, so a coincidental
 value match with a real id never causes a false substitution.
2. KEY ORDER + correlation stripping. Each command's own input Hash (and any
 nested Hash, e.g. `byType`) is recursively re-sorted by key so two batches that
 differ only in the Hash literal's construction order compare equal, and any
 `CORRELATION_KEYS` entry (never part of the compared shape) is dropped.

Two normalised batches are STRUCTURALLY EQUIVALENT iff Normalizer.normalize(a) == Normalizer.normalize(b) -- byte-identical once serialised (to_json), per the DSL-08 acceptance test.

Constant Summary collapse

REFERENCE_KEYS =

Keys whose String value addresses a node (mint or reference), across every WorkflowCommand input class this repo ships plus the downstream writers' own commands (placeholderId/stageId/sectionId/dataFieldId/data_field_id/optionId/ forceId/referenceId/anchorId/id) -- verified against every VALID_KEYS list under lib/ecoportal/api/graphql/input/workflow_command/. Deliberately a CLOSED, named set (not "every String") so a literal content String (a label, a script, a URL) is never mistaken for a reference.

%i[
  placeholderId stageId sectionId dataFieldId data_field_id optionId
  forceId referenceId anchorId id
].freeze
CORRELATION_KEYS =

Fields that exist only for request bookkeeping, never part of the compared shape.

%i[clientMutationId correlationId].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.normalize(commands) ⇒ Array<Hash>



53
54
55
# File 'lib/ecoportal/api/graphql/model/template/command_normalizer.rb', line 53

def self.normalize(commands)
  new.normalize(commands)
end

Instance Method Details

#normalize(commands) ⇒ Object



57
58
59
60
61
# File 'lib/ecoportal/api/graphql/model/template/command_normalizer.rb', line 57

def normalize(commands)
  @tokens     = {}
  @next_index = 0
  Array(commands).map { |command| normalize_command(command) }
end