Skip to main content

Blue Language Specification

This document provides the technical specification for Blue Language, defining core structures, behaviors, and rules that compliant processors must implement.

1. Document Structure

1.1 Base Format

Blue documents use YAML or JSON as their foundation. Any valid YAML or JSON document is a valid Blue document if it adheres to the conventions defined in this specification.

1.2 Node Structure

A node is the fundamental unit in Blue. Every node belongs to exactly one of these categories:

  1. Value Node: Contains a primitive value (Integer, Text, Double, Boolean)
  2. List Node: Contains an ordered collection of other nodes
  3. Structure Node: Contains named references to other nodes

2. Reserved Attributes

Blue reserves several attribute names with special meaning:

AttributePurpose
nameThe name of the element
descriptionA textual description of the element
typeReference to another document/type that this element inherits from
valueThe primitive value of the element
blueIdThe content-based identifier of the element
contractsRules that define how the document responds to events
blueTransformations for Blue processors
itemsList items (for list nodes only)
itemTypeType constraint for list items
keyTypeType constraint for dictionary keys
valueTypeType constraint for dictionary values

These attributes must only be used according to their intended purpose to ensure consistent behavior across processors.

2.1 Special Text Attributes

The name and description attributes have special properties:

  • Always treated as text values
  • Are part of the node itself (not references to other nodes)
  • Used directly in BlueId calculation
  • Cannot be referenced as separate nodes

For example:

# Correct
name: Some Name
otherTextParam:
value: Some Value
type: Text

# Also correct - referencing a node with BlueId
name: Some Name
otherTextParam:
blueId: CLthNx8MWUfPWr1xXzSivsxjye9uQyi77Ep6LGPLvYpM

3. Node Categories and Constraints

3.1 Value Nodes

A value node must:

  • Have a value property
  • Not have items or properties
  • Be of a basic type (Integer, Text, Double, Boolean) or a subtype

Example:

myInteger:
value: 42
type:
blueId: DHmxTkFbXePZHCHCYmQr2dSzcNLcryFVjXVHkdQrrZr8 # Integer

3.2 List Nodes

A list node must:

  • Have an items property containing a list
  • Not have value or properties
  • Optionally have an itemType constraint

Example:

myList:
items:
- 1
- 2
- 3
itemType:
blueId: DHmxTkFbXePZHCHCYmQr2dSzcNLcryFVjXVHkdQrrZr8 # Integer

3.3 Structure Nodes

A structure node must:

  • Have properties referencing other nodes
  • Not have value or items

Example:

person:
name: John Doe
age: 30
address:
street: 123 Main St
city: Anytown

4. Type System

4.1 Primitive Types

Blue defines four primitive types:

TypeBlueIdDescriptionExample Values
TextF92yo19rCcbBoBSpUA5LRxpfDejJDAaP1PRxxbWAraVPText strings"Hello"
IntegerDHmxTkFbXePZHCHCYmQr2dSzcNLcryFVjXVHkdQrrZr8Arbitrary precision integer42, 9007199254740991
Double68ryJtnmui4j5rCZWUnkZ3DChtmEb7Z9F8atn1mBSM3LIEEE 754 double-precision3.14159
BooleanEL6AjrbJsxTWRTPzY8WR8Y2zAMXRbydQj83PcZwuAHboLogical true/falsetrue, false

4.2 Integer Representation

Integers in Blue have arbitrary precision:

  • Values within JavaScript safe integer range (-9007199254740991 to 9007199254740991) are stored natively
  • Values outside this range are stored as strings with the Integer type

Example:

x1:
value: 123
type:
blueId: DHmxTkFbXePZHCHCYmQr2dSzcNLcryFVjXVHkdQrrZr8 # Integer

x2:
value: "132452345234524739582739458723948572934875"
type:
blueId: DHmxTkFbXePZHCHCYmQr2dSzcNLcryFVjXVHkdQrrZr8 # Integer

4.3 Type Inheritance

When a node specifies a type, it inherits all properties from the referenced type. If document B specifies type: A, then B is considered a subtype of A, inheriting its properties.

4.4 Type Extension Rules

When extending a type:

  1. Fixed values in the parent type cannot be overridden
  2. New properties can be added
  3. Properties with no fixed values can be assigned values
  4. Type compatibility must be maintained (child properties must use the same or compatible subtypes)

5. BlueId Calculation

5.1 BlueId Definition

A BlueId is a content-based identifier calculated for every node in a Blue document. It uniquely identifies a node based on its semantic content.

5.2 BlueId Algorithm

The BlueId calculation algorithm works as follows:

  1. Clean the structure: Remove null values

  2. For primitive values (String, Number, Boolean):

    • Hash the string representation directly
  3. For maps (structure nodes):

    • If the map contains a blueId key, use its value directly
    • Otherwise:
      • Keep name, value, and description as direct values
      • Replace all other properties with their BlueId references
      • Hash this transformed map
  4. For lists:

    • If the list has only one item, return the BlueId of that item
    • Otherwise:
      • Calculate the BlueId of the sublist excluding the last element
      • Calculate the BlueId of the last element
      • Create a list with these two BlueIds and hash it

Here is the complete algorithm in Java:

public String calculate(Object object) {
Object cleanedObject = cleanStructure(object);
if (cleanedObject instanceof String || cleanedObject instanceof Number || cleanedObject instanceof Boolean) {
return hashProvider.apply(cleanedObject.toString());
} else if (cleanedObject instanceof Map) {
return calculateMap((Map<String, Object>) cleanedObject);
} else if (cleanedObject instanceof List) {
return calculateList((List<Object>) cleanedObject);
}
throw new IllegalArgumentException(
"Object must be a String, Number, Boolean, List or Map - found " + cleanedObject.getClass());
}

private String calculateMap(Map<String, Object> map) {
if (map.containsKey(OBJECT_BLUE_ID)) {
return (String) map.get(OBJECT_BLUE_ID);
}

Map<String, Object> hashes = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
if (OBJECT_NAME.equals(key) || OBJECT_VALUE.equals(key) || OBJECT_DESCRIPTION.equals(key)) {
hashes.put(key, entry.getValue());
} else {
String blueId = calculate(entry.getValue());
hashes.put(key, Collections.singletonMap("blueId", blueId));
}
}
return hashProvider.apply(hashes);
}

private String calculateList(List<Object> list) {
if (list.size() == 1) {
return calculate(list.get(0));
}

List<Object> subList = list.subList(0, list.size() - 1);
String hashOfSubList = calculateList(subList);

Object lastElement = list.get(list.size() - 1);
String hashOfLastElement = calculate(lastElement);

List<Map<String, String>> result = Arrays.asList(
Collections.singletonMap("blueId", hashOfSubList),
Collections.singletonMap("blueId", hashOfLastElement));
return hashProvider.apply(result);
}

5.3 Hash Function

The default hash function is Base58-encoded SHA-256, but the blue directive can specify an alternative hash algorithm.

6. Circular References

Circular references occur when two or more nodes reference each other, creating a dependency cycle.

- name: A
x:
type:
blueId: this#1 # References B
aVal:
constraints:
maxLength: 4
- name: B
y:
type:
blueId: this#0 # References A
bVal:
constraints:
maxLength: 4
bConst: xyz

When calculating BlueIds with circular references:

  1. Temporary markers in the format this#n refer to nodes within the current calculation context
  2. The final BlueIds are calculated simultaneously, each aware of the others
  3. During extension and resolution, cycles are detected and handled appropriately

Example usage with circular types:

name: Some
a:
type:
blueId: [A's BlueId]
aVal: abcd
x:
bVal: abcd

7. Document Operations

7.1 Resolution

Resolving a node involves expanding all fields from its subtypes and inherited documents:

# Define A
name: A
x: 10
y:
type: Integer
---
# Define B inheriting from A
name: B
type: A
y: 5
z: 5

# After resolving B, it will have:
# - x: 10 (inherited from A)
# - y: 5 (overridden)
# - z: 5 (additional property)

7.2 Extension

Extending a node populates it with additional information from its referenced types or blueIds without fully resolving all inherited properties:

Node oneLevelExtended = blue.extend(node, PathLimits.withSinglePath("/*"));

7.3 Simplification

Simplifying a node reduces it to its minimal form by removing inherited properties that match defaults from parent types:

# Resolved Node B
name: B
type: A
x: 10 # Inherited value
y: 5
z: 5
---
# After simplification, Node B becomes:
name: B
type: A
y: 5 # Only differs from A
z: 5 # Not in A

8. Blue Directive

The blue directive specifies transformations to apply during preprocessing. For complete details, see The Blue Directive.

9. Java Implementation Model

The Java reference implementation models nodes as:

public class Node implements Cloneable {
private String name;
private String description;
private Node type;
private Node itemType;
private Node keyType;
private Node valueType;
private Object value;
private List<Node> items;
private Map<String, Node> properties;
private String blueId;
private Node blue;
// Methods omitted
}

This structure enforces that:

  • A node is either a value node, a list node, or a structure node
  • Special attributes like name and description are treated as strings
  • BlueId can be cached with the node after calculation

10. Processing Pipeline

When a Blue processor handles a document, it follows this pipeline:

  1. Parsing: Convert from YAML/JSON to node structure
  2. Preprocessing: Apply transformations from blue directive
  3. BlueId Calculation: Calculate BlueIds for all nodes
  4. Reference Resolution: Resolve BlueId references
  5. Type Resolution: Apply type inheritance
  6. Validation: Verify type constraints
  7. Contract Processing: Process contract definitions (if applicable)

11. Error Conditions

A compliant Blue processor must generate errors for:

  • Type incompatibilities (attempting to override a parent type)
  • Constraint violations (exceeding maxLength, etc.)
  • Invalid attribute usage (using reserved attributes incorrectly)
  • BlueId calculation failures
  • Circular reference issues not properly resolved
  • Ambiguous or conflicting type definitions