rules

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 27, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package rules holds the individual SemanticRule implementations that fire PRISM_SPEC_* error codes.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AggCompat

type AggCompat struct{}

AggCompat implements PRISM_SPEC_002: aggregate operations require the target field to be of a compatible measure type. Numeric aggregates (mean, sum, etc.) need quantitative or temporal fields; counting ops accept anything.

func (AggCompat) Check

func (AggCompat) Check(s *spec.Spec, schemas validate.SchemaLookup) []*errors.AppError

Check inspects:

  • encoding-channel inline aggregates (e.g. y: {field: x, aggregate: mean}),
  • aggregate transform ops.

As with PRISM_SPEC_001, the rule no-ops when the dataset schema is not resolvable (e.g. EmptyLookup or unbound inline values).

func (AggCompat) Code

func (AggCompat) Code() string

Code returns PRISM_SPEC_002.

type AnimationEasingKnown

type AnimationEasingKnown struct{}

AnimationEasingKnown implements PRISM_SPEC_022: when an animation block declares an easing, the name must be one of spec.AnimationEasings. An empty / omitted easing is fine (the encoder applies the default at scene-emit time).

func (AnimationEasingKnown) Check

Check fires when animation.easing is non-empty and unrecognised.

func (AnimationEasingKnown) Code

Code returns PRISM_SPEC_022.

type AnimationKeyPresent

type AnimationKeyPresent struct{}

AnimationKeyPresent implements PRISM_SPEC_023: when an animation block is declared, the spec must expose a join key. Today the only supported source is an encoding channel with key:true; future versions may accept a top-level data.key field. Composition forms (layer / concat / facet / repeat) inherit animation from the parent spec, so the rule checks the current node's encoding plus any immediate child specs that override animation.

func (AnimationKeyPresent) Check

Check fires when s.Animation is set but no descendant encoding declares key:true.

func (AnimationKeyPresent) Code

func (AnimationKeyPresent) Code() string

Code returns PRISM_SPEC_023.

type AnimationKeyUnique

type AnimationKeyUnique struct{}

AnimationKeyUnique implements PRISM_SPEC_024: at most one encoding channel in any given spec node may carry key:true. Composite keys are not supported in v1. The rule walks composition children (layer / concat / facet child) and emits one error per node that exceeds the cap.

func (AnimationKeyUnique) Check

Check fires for every encoding block whose channels carry key:true on more than one entry.

func (AnimationKeyUnique) Code

func (AnimationKeyUnique) Code() string

Code returns PRISM_SPEC_024.

type ChannelForMark

type ChannelForMark struct{}

ChannelForMark implements PRISM_SPEC_003: each encoding channel must be supported by the spec's mark type. The supported set is per-mark; for example, theta/radius are supported by arc/pie/donut but not by bar.

func (ChannelForMark) Check

Check inspects every channel set on s.Encoding against allowedChannelsForMark(mark).

func (ChannelForMark) Code

func (ChannelForMark) Code() string

Code returns PRISM_SPEC_003.

type CompositeMarkEncoding

type CompositeMarkEncoding struct{}

CompositeMarkEncoding implements PRISM_SPEC_013: composite marks (histogram, heatmap, boxplot, violin) require a specific shape of encoding channels. Pie / donut are covered by PRISM_SPEC_008 (PieDonutEncoding); this rule covers the cartesian-axis composites.

Rules per mark (D059–D062):

  • histogram: requires a single quantitative x channel.
  • heatmap: requires both x and y to be bound.
  • boxplot: requires exactly one categorical axis (x or y) and the other axis quantitative.
  • violin: same as boxplot.

func (CompositeMarkEncoding) Check

Check inspects the spec's mark + encoding against the per-mark shape requirements. Emits one PRISM_SPEC_013 per violation.

func (CompositeMarkEncoding) Code

Code returns PRISM_SPEC_013.

type ConditionSelectionRef

type ConditionSelectionRef struct{}

ConditionSelectionRef implements PRISM_SPEC_025: every `selection` name referenced from a condition entry must resolve to a declared selection in the spec's "selection" block.

func (ConditionSelectionRef) Check

Check walks every condition-bearing channel and reports unresolved selection references.

func (ConditionSelectionRef) Code

Code returns PRISM_SPEC_025.

type ConditionTestParses

type ConditionTestParses struct{}

ConditionTestParses implements PRISM_SPEC_026: every `test` expression in a condition entry must parse via the Pulse expression parser (mirroring PRISM_SPEC_006 for transforms).

func (ConditionTestParses) Check

Check walks every condition-bearing channel and tries to parse each non-empty test expression. Reuses the parser shim from ExpressionParses so the syntax surface stays in sync with Pulse.

func (ConditionTestParses) Code

func (ConditionTestParses) Code() string

Code returns PRISM_SPEC_026.

type ConditionValueOrBinding

type ConditionValueOrBinding struct{}

ConditionValueOrBinding implements PRISM_SPEC_027: a condition entry must carry exactly one of {value, field}. Both set or neither set fails — except that a selection-form entry with neither value nor field is allowed: it implicitly inherits the channel's own field binding. test-form entries always require value or field.

func (ConditionValueOrBinding) Check

Check walks every condition-bearing channel and flags entries with invalid value/field combinations.

func (ConditionValueOrBinding) Code

Code returns PRISM_SPEC_027.

type DatasetRef

type DatasetRef struct{}

DatasetRef implements PRISM_SPEC_005: every named dataset reference (in data.name, transform.data, transform.join.with, transform.union) must resolve to a dataset declared in the spec's "datasets" map, in the registered SchemaLookup, or in an earlier transform's "as" output.

func (DatasetRef) Check

func (DatasetRef) Check(s *spec.Spec, schemas validate.SchemaLookup) []*errors.AppError

Check walks the spec collecting dataset references and reports any that do not resolve. Recurses into child layer/concat/facet/repeat specs.

func (DatasetRef) Code

func (DatasetRef) Code() string

Code returns PRISM_SPEC_005.

type ExpressionParses

type ExpressionParses struct{}

ExpressionParses implements PRISM_SPEC_006: every Pulse expression (filter predicates, calculate expressions) must parse successfully.

TODO(pulse): switch from expr-lang/expr to Pulse's wrapper as soon as Pulse exposes a public expression parser. Pulse 0.8.4 uses expr-lang/expr v1.17.8 internally (see processing/filterer.go) but does not export the compiler/options. Until then this rule depends directly on the same expr-lang/expr version so the syntax surface matches what Pulse runs at execution time.

func (ExpressionParses) Check

Check inspects every filter and calculate expression and tries to parse it. The selection:<name> shorthand used by SelectionRef is stripped before parsing so expressions that mix it with Pulse syntax still validate as expressions.

func (ExpressionParses) Code

func (ExpressionParses) Code() string

Code returns PRISM_SPEC_006.

type FieldExists

type FieldExists struct{}

FieldExists implements PRISM_SPEC_001: every encoded field must exist in the source dataset's schema (or be the output of a transform within the spec). With an EmptyLookup (no real Pulse source bound), the rule is a no-op — the resolver in P02 turns this into a hard check.

func (FieldExists) Check

func (FieldExists) Check(s *spec.Spec, schemas validate.SchemaLookup) []*errors.AppError

Check inspects every encoding channel's "field" reference against the schema for the dataset bound by the leaf spec.

func (FieldExists) Code

func (FieldExists) Code() string

Code returns PRISM_SPEC_001.

type FormatStringValid

type FormatStringValid struct{}

FormatStringValid implements PRISM_SPEC_011: every channel.format, axis.format, and legend.format must parse as a valid d3-format specifier (subset supported in encode/format).

func (FormatStringValid) Check

Check walks every channel inspecting Format strings + nested axis / legend format strings.

func (FormatStringValid) Code

func (FormatStringValid) Code() string

Code returns PRISM_SPEC_011.

type GeoProjection

type GeoProjection struct{}

GeoProjection ensures the spec's projection block is valid and that geo marks have both a projection and the right channel binding.

func (GeoProjection) Check

func (GeoProjection) Code

func (GeoProjection) Code() string

type ImageURLAllowed

type ImageURLAllowed struct{}

ImageURLAllowed implements PRISM_SPEC_016: image marks may only reference data: URLs or relative paths. Remote URLs (http, https, ftp, file, gs, s3, ...) are rejected at validate time per D068 so the encoder + renderer stay network-free (matches PROJECT.md offline-first principle).

func (ImageURLAllowed) Check

Check fires when an image mark's URL string is non-empty AND is neither a data: URL nor a relative path.

func (ImageURLAllowed) Code

func (ImageURLAllowed) Code() string

Code returns PRISM_SPEC_016.

type LogScalePositiveDomain

type LogScalePositiveDomain struct{}

LogScalePositiveDomain implements PRISM_SPEC_010: a channel that declares scale.type=log must bind a field whose values (when available via inline data) are strictly positive. The rule walks every position + mark channel; for each that carries scale.type=log and a field name resolvable through inline data.values, it inspects the values and flags any non-positive entry.

When the dataset is external (Pulse-backed, GCS, etc.) the rule no-ops — the encoder's per-row guard surfaces the same code at render time via scale.LogScale.Apply / encode.resolveLog.

func (LogScalePositiveDomain) Check

Check inspects every channel with scale.type=log. Returns PRISM_SPEC_010 for each field whose inline values include a zero or negative.

func (LogScalePositiveDomain) Code

Code returns PRISM_SPEC_010.

type PathDNonEmpty

type PathDNonEmpty struct{}

PathDNonEmpty implements PRISM_SPEC_017: the path mark's `d` attribute (carried as MarkDef.Path on the spec) must be a non-empty SVG path string. Empty / whitespace-only strings are rejected at validate time.

func (PathDNonEmpty) Check

Check fires when the spec's mark is "path" and the d-string is empty or whitespace-only.

func (PathDNonEmpty) Code

func (PathDNonEmpty) Code() string

Code returns PRISM_SPEC_017.

type PieDonutEncoding

type PieDonutEncoding struct{}

PieDonutEncoding implements PRISM_SPEC_008: pie and donut marks (and the underlying arc mark when used in their composite form) must encode value via theta and category via color, never x/y. PRISM_SPEC_003 catches "channel not valid for mark" generically; this rule provides a more specific message tailored to the pie/donut workflow.

func (PieDonutEncoding) Check

Check fires when:

  • mark is pie or donut and the spec uses x or y, OR
  • mark is pie or donut and no theta encoding is present.

func (PieDonutEncoding) Code

func (PieDonutEncoding) Code() string

Code returns PRISM_SPEC_008.

type RepeatSubstitution

type RepeatSubstitution struct{}

RepeatSubstitution implements PRISM_SPEC_012 at validate time. When a `repeat` block's child spec carries an encoding channel with `{"field": {"repeat": <axis>}}` substitution that references an axis the parent did NOT declare on the repeat block, the rule fires before the builder runs.

The build-time substitution walker (plan/build/composite.go) also catches this case — defense-in-depth, mirroring the layered scale rule (P08) — but firing at validate keeps the error visible through `prism validate` without driving the full plan pipeline.

func (RepeatSubstitution) Check

Check walks every `repeat` block in the spec (top-level + nested inside facet / repeat / layer / concat children) and asserts that each substitution's axis is declared on its nearest-enclosing repeat block.

func (RepeatSubstitution) Code

func (RepeatSubstitution) Code() string

Code returns PRISM_SPEC_012.

type ResolveScaleCompat

type ResolveScaleCompat struct{}

ResolveScaleCompat implements PRISM_PLAN_005 at validate time. When a composite spec uses `resolve.scale.<channel>: "shared"` AND the layers declare incompatible types on that channel (e.g. one layer nominal + another quantitative on `y`), the rule fires before the encoder runs. The encoder also catches the same issue (defense-in- depth via encode/resolve.Unify) so dynamic-type cases — where the spec leaves `type` implicit — are still trapped.

The rule walks only the spec's top-level `layer` array; concat / hconcat / vconcat children are full charts that resolve scales independently per cell (see D050, D053), so cross-panel sharing is not in scope here.

func (ResolveScaleCompat) Check

Check inspects every shared channel in resolve.scale and asserts type agreement across the layer array. Channels where any layer omits an explicit `encoding.<ch>.type` are skipped — the encoder's table-driven inference covers that case.

func (ResolveScaleCompat) Code

func (ResolveScaleCompat) Code() string

Code returns PRISM_PLAN_005.

type SankeyChannels

type SankeyChannels struct{}

SankeyChannels implements PRISM_SPEC_018: sankey marks require source, target, and value channel bindings (per D064 flat-table input form). Missing channels raise a single error listing every missing name.

func (SankeyChannels) Check

Check fires when mark is sankey and any of source / target / value is missing or has an empty Field.

func (SankeyChannels) Code

func (SankeyChannels) Code() string

Code returns PRISM_SPEC_018.

type ScaleTypeCompat

type ScaleTypeCompat struct{}

ScaleTypeCompat implements PRISM_SPEC_007: an explicit scale type on an encoding channel must be compatible with the field's measure type. log/pow/sqrt/linear belong on quantitative; time on temporal; band / point / ordinal on nominal/ordinal.

func (ScaleTypeCompat) Check

Check inspects every channel with an inline scale.type and validates it against the channel's declared "type" (nominal/ordinal/quantitative/ temporal). If the channel has no type but the dataset is known, the rule falls back to the source field's type. No-ops when neither source is available.

func (ScaleTypeCompat) Code

func (ScaleTypeCompat) Code() string

Code returns PRISM_SPEC_007.

type SchemaRef

type SchemaRef struct{}

SchemaRef implements PRISM_SPEC_009: the spec's $schema value must reference a known Prism schema location. Accepted forms:

  • The canonical URN urn:prism:schema:v1:spec.
  • A relative or absolute path ending in spec.schema.json.
  • A file:// URL ending in spec.schema.json.

func (SchemaRef) Check

Check fires when s.Schema does not match any accepted form.

func (SchemaRef) Code

func (SchemaRef) Code() string

Code returns PRISM_SPEC_009.

type SelectionEncodingChannel

type SelectionEncodingChannel struct{}

SelectionEncodingChannel implements PRISM_SPEC_019: every channel listed in a selection's `encodings` array must be bound in the spec's encoding block.

Both point + interval selections honour the rule. The channel name is case-sensitive (lower-case per the JSON schema enum).

func (SelectionEncodingChannel) Check

Check walks every selection's Encodings list and confirms each entry resolves to a bound channel in s.Encoding.

func (SelectionEncodingChannel) Code

Code returns PRISM_SPEC_019.

type SelectionIntervalChannel

type SelectionIntervalChannel struct{}

SelectionIntervalChannel implements PRISM_SPEC_020: an interval selection's `encodings` list must contain only position channels (x | y | x2 | y2 | theta). Color / size / shape intervals are not supported in v1 — those use cases route through point selections.

func (SelectionIntervalChannel) Check

Check walks every interval selection's encodings list and reports any non-position entry.

func (SelectionIntervalChannel) Code

Code returns PRISM_SPEC_020.

type SelectionRef

type SelectionRef struct{}

SelectionRef implements PRISM_SPEC_004: every reference to a named selection must resolve to a selection declared in the spec's "selection" block.

Selection references in v1 appear as:

  • The substring "selection:<name>" inside a filter expression (the convention adopted for Pulse-expression-driven specs).
  • Future: explicit references in condition encodings (deferred to v2).

func (SelectionRef) Check

Check scans filter expressions for selection references and reports any that do not match a declared selection.

func (SelectionRef) Code

func (SelectionRef) Code() string

Code returns PRISM_SPEC_004.

type TreeChannels

type TreeChannels struct{}

TreeChannels implements PRISM_SPEC_028: tree, dendrogram, and network marks require source + target channel bindings (per the flat-table input form). Missing channels raise a single error listing every missing name.

func (TreeChannels) Check

Check fires when mark is tree / dendrogram / network and either of source / target is missing or has an empty Field.

func (TreeChannels) Code

func (TreeChannels) Code() string

Code returns PRISM_SPEC_028.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL