NEON Format

NEON is a human-readable structured data format. In Nette, it is used for configuration files. It is also used for structured data such as settings, language translations, etc. Try it on the sandbox.

NEON stands for Nette Object Notation. It is less complex and cumbersome than XML or JSON, but provides similar capabilities. It is very similar to YAML. The main advantage is that NEON has so-called entities, thanks to which the configuration of DI services is so sexy. And it allows tabs for indentation.

NEON is built from the ground up to be easy to use.

Integration

Implementations

NEON can be read and written in several languages:

The format is written down in a language-neutral specification together with a conformance corpus, a set of test cases that every implementation runs. If you are writing a NEON library for another language, the corpus is there for you to use.

Syntax

A file written in NEON usually represents a sequence or a mapping.

Mappings

A mapping is a set of key-value pairs; in PHP, it would be called an associative array. Each pair is written as key: value, a space after : is required. The value can be anything: string, number, boolean, null, sequence, or another mapping.

street: 742 Evergreen Terrace
city: Springfield
country: USA

In PHP, the same structure would be written as:

[ // PHP
	'street' => '742 Evergreen Terrace',
	'city' => 'Springfield',
	'country' => 'USA',
]

This notation is called block notation because all items are on separate lines and have the same indentation (none in this case). NEON also supports an inline representation for mappings, which is enclosed in brackets, indentation plays no role, and the separator for elements is either a comma or a newline:

{street: 742 Evergreen Terrace, city: Springfield, country: USA}

The same written on multiple lines (indentation does not matter):

{
	street: 742 Evergreen Terrace
		city: Springfield, country: USA
}

A value may also stand on the line after its key, as in JSON:

{
	street:
		742 Evergreen Terrace
}

Alternatively, = can be used instead of : , both in block and inline notation:

{street=742 Evergreen Terrace, city=Springfield, country=USA}

Sequences

Sequences are indexed arrays in PHP. They are written as lines starting with a hyphen - followed by a space. Again, the value can be anything: string, number, boolean, null, sequence, or another mapping.

- Cat
- Dog
- Goldfish

In PHP, the same structure would be written as:

[ // PHP
	'Cat',
	'Dog',
	'Goldfish',
]

This notation is called block notation because all items are on separate lines and have the same indentation (none in this case). NEON also supports an inline representation for sequences, which is enclosed in brackets, indentation plays no role, and the separator for elements is either a comma or a newline:

[Cat, Dog, Goldfish]

The same written on multiple lines (indentation does not matter):

[
	Cat, Dog
		Goldfish
]

Hyphens (bullets) cannot be used in the inline representation.

Combinations

Values of mappings and sequences can be other mappings and sequences. The level of indentation plays a major role. In the following example, the hyphen used to indicate sequence items has a greater indentation than the pets key, so the items become the value of the first line:

pets:
   - Cat
   - Dog
cars:
   - Volvo
   - Skoda

In PHP, the same structure would be written as:

[ // PHP
	'pets' => [
		'Cat',
		'Dog',
	],
	'cars' => [
		'Volvo',
		'Skoda',
	],
]

It is possible to combine block and inline notation:

pets: [Cat, Dog]
cars: [
	Volvo,
	Skoda,
]

Block notation cannot be used inside an inline notation; this does not work:

item: [
	pets:
	 - Cat     # THIS IS NOT POSSIBLE!!!
	 - Dog
]

In the previous case, we wrote a mapping whose elements were sequences. Now, let's try it the other way around and create a sequence containing mappings:

-
	name: John
	age: 35
-
	name: Peter
	age: 28

It's not necessary for the hyphens to be on separate lines; they can also be placed like this:

- name: John
  age: 35
- name: Peter
  age: 28

It's up to you whether you align the keys in a column using spaces or use a tab character.

Because PHP uses the same structure for mappings and sequences (i.e., arrays), both can be merged. The indentation is the same this time:

- Cat
street: 742 Evergreen Terrace
- Goldfish

In PHP, the same structure would be written as:

[ // PHP
	'Cat',
	'street' => '742 Evergreen Terrace',
	'Goldfish',
]

An item without a key gets an integer key one greater than the greatest integer key before it, as in PHP. So {5: Cat, Dog} gives Dog the key 6.

Strings

Strings in NEON can be enclosed in single or double quotes. But as you can see, they can also be without quotes.

- An unquoted string in NEON
- 'A single-quoted string in NEON'
- "A double-quoted string in NEON"

If the string contains characters ` # " ' ` , : = - [ ] { } ( ) ` that could be confused with NEON syntax, it must be enclosed in quotes. We recommend using single quotes because they do not use escaping. If you need to include a quote character in such a string, double it:

'A single quote '' inside a single-quoted string'

Double quotes allow you to use escape sequences to write special characters using backslashes \. All escape sequences supported by the JSON format are supported, plus \_, which represents a non-breaking space, i.e., \u00A0.

- "\t \n \r \f \b \" \\ \/ \_"
- "\u00A9"

There are other cases where you need to enclose strings in quotes:

  • they start or end with spaces
  • they look like numbers, booleans, or null
  • NEON would interpret them as dates

Multiline Strings

A multiline string begins and ends with triple quotes on separate lines. The indentation of the first non-empty line is removed from all lines:

'''
	first line
		second line
	third line
	'''

In PHP, we would write the same as:

"first line\n\tsecond line\nthird line" // PHP

A line indented less than the first non-empty line keeps its indentation whole. A line of spaces or tabs only is not empty, so when it comes first, it sets the indentation.

Escape sequences work only for strings enclosed in double quotes instead of apostrophes:

"""
	Copyright \u00A9
"""

A backslash at the end of a line does not join it with the next one, it stays in the string.

Numbers

NEON understands numbers written in scientific notation and also numbers in binary, octal, and hexadecimal bases:

- 12         # integer
- 12.3       # float
- +1.2e-34   # exponential number

- 0b11010    # binary number
- 0o666      # octal number
- 0x7A       # hexadecimal number

The prefixes 0b, 0o and 0x are written in lowercase and without a sign, so 0X10 and -0x1 are strings. Leading zeros do not mean an octal number: 0777 is 777. Underscores between digits are not allowed, 1_000 is a string.

Nulls

Null can be expressed in NEON using null or by omitting the value. Variants with a capital first letter or all uppercase letters are also allowed (Null, NULL).

a: null
b:

Booleans

Boolean values are expressed in NEON using true / false or yes / no. Variants with a capital first letter or all uppercase letters are also allowed (True, TRUE, False, FALSE, Yes, YES, No, NO).

[true, TRUE, True, false, yes, no]

The words on and off, which YAML 1.1 reads as booleans, are ordinary strings in NEON.

Dates

NEON uses the following formats to express dates, and the PHP library converts them to DateTimeImmutable objects:

- 2016-06-03                  # date
- 2016-06-03 19:00:00         # date & time
- 2016-06-03 19:00:00.1234    # date & microtime
- 2016-06-03 19:00:00 +0200   # date & time & timezone
- 2016-06-03 19:00:00 +02:00  # date & time & timezone
- 2016-06-03T19:00:00Z        # ISO 8601 with T and the UTC zone

A literal that looks like a date but is not a valid one, such as 2024-02-30, is not converted and stays a string.

Entities

An entity is a structure that resembles a function call:

Column(type: int, nulls: yes)

In PHP, it is parsed as a Nette\Neon\Entity object:

// PHP
new Nette\Neon\Entity('Column', ['type' => 'int', 'nulls' => true])

Entities can also be chained:

Column(type: int, nulls: yes) Field(id: 1)

This is parsed in PHP as follows:

// PHP
new Nette\Neon\Entity(Nette\Neon\Neon::Chain, [
	new Nette\Neon\Entity('Column', ['type' => 'int', 'nulls' => true]),
	new Nette\Neon\Entity('Field', ['id' => 1]),
])

The value of Neon::Chain is !!chain, so this name is reserved and cannot be used for an entity of your own.

Inside the parentheses, the rules for inline notation used for mappings and sequences apply, so it can be multiline, and commas are not necessary:

Column(
	type: int
	nulls: yes
)

Comments

Comments start with # and all subsequent characters to the right are ignored:

# this line will be ignored by the interpreter
street: 742 Evergreen Terrace
city: Springfield  # this is ignored too
country: USA

NEON versus JSON

JSON is almost a subset of NEON, so practically any JSON can be parsed as NEON. The only exception is a colon at the start of a line glued to its value, such as "a" followed by a line with :1, which NEON reads as the string :1:

{
"php": {
	"date.timezone": "Europe\/Prague",
	"zlib.output_compression": true
},
"database": {
	"driver": "mysql",
	"username": "root",
	"password": "password123"
},
"users": [
	"Dave", "Kryten", "Rimmer"
]
}

What if we omitted the quotes?

{
php: {
	date.timezone: Europe/Prague,
	zlib.output_compression: true
},
database: {
	driver: mysql,
	username: root,
	password: password123
},
users: [
	Dave, Kryten, Rimmer
]
}

How about braces and commas?

php:
	date.timezone: Europe/Prague
	zlib.output_compression: true

database:
	driver: mysql
	username: root
	password: password123

users: [
	Dave, Kryten, Rimmer
]

Aren't lists with bullets more readable?

php:
	date.timezone: Europe/Prague
	zlib.output_compression: true

database:
	driver: mysql
	username: root
	password: password123

users:
	- Dave
	- Kryten
	- Rimmer

Shall we add comments?

# my web application config

php:
	date.timezone: Europe/Prague
	zlib.output_compression: true  # use gzip

database:
	driver: mysql
	username: root
	password: password123

users:
	- Dave
	- Kryten
	- Rimmer

Hooray, now you know the NEON syntax!