NEON vs. YAML and How to Migrate Between Them

This post was updated at December 2018 with fresh know-how.
What is new?

Updated with EasyCodingStandard 5, Neon to YAML migration and checkers to services migration.


Do you know *.neon format? It's config file format created in Czech Republic by David Grudl (author of Nette) and if you're foreigner, you might know it from or EasyCodingStandard and PHPStan. Even suggested as composer.neon.

And *.yaml is similar format used almost everywhere else.

You spot the suffix is different, but what about syntax differences? And which one is better?

None of them is perfect, they both have strong parts and weak parts. But the more I travel to abroad conferences, meetups or repositories, the more I hear nobody understand differences between them or their advantages to each other. Since I meet mainly with Symfony and Nette code, I had to investigate them a bit deeper.

There are no solutions. There are only trade-offs.
Thomas Sowell, author of A Conflict of Visions: Ideological Origins of Political Struggles

Here is a summary of what I found and how to migrate to each other. I'll write about differences and places, where syntax fail me the most.

How is Syntax Differ?

70 % of syntax is similar:

services:
    Symplify\CodingStandard\Fixer\Import\ImportNamespacedNameFixer: ~

But what about?

items:
  -
    - { key: value }

Of course you can Google documentation and try to understand it. But documentation is incomplete or for older version than you use. The best way to learn it for me is with online parsers:


1. Tabs vs. Spaces

Neon

As neon was born as free format, it allows to use both spaces and tabs.

Yaml

Only spaces are allowed. Since most of projects have coding standards, I prefer using one format in whole code.


2. Magic List Combination vs. Single Type

services:
    - SomeService
    SomeService: ~

Neon

Could you guess the output? 1 item? Syntax error?

array (1)
    services => array (2)
        0 => "SomeService" (11)
        SomeService => "~"

Neon allows to combine indexed arrays and lists. And do you work with or create with such lists in PHP?

Yaml

Parsing would fail there, because Yaml allows only one approach:

services:
    - SomeService
    - SomeService

# with 2 items in array

or

services:
    SomeService: ~
    SomeService: ~

# with 1 item

This difference is one of the biggest WTFs, because I had to think about format and possible merge error every time I used lists... or indexed arrays... or is it arrays? Uff.


3. Content on Multi-lines

I write posts in Statie, where you can use Yaml to configure per-post variables like perex:

Neon

perex: '''
    This is long multiline perex,
that takes too much space.
'''

Note it can be aligned to left side.

Yaml

perex: |
    This is long multiline perex,
    that takes too much space.

But here it must be indented on every line.


4. Very Complex Syntax

Neon

In Neon you can use entities and do this:

someValue: Column(type=int, nulls=true)

Could you guess what it is? Parameters, arguments, service decoration?

array (1)
    someValue => Nette\Neon\Entity
        value => "Column" (6)
        attributes => array (2)
            type => "int" (3)
            nulls => true

Personally I prefer explicit, clear naming combined with easier scalability:

someValue:
    value: "Column"
    attributes:
        type: "int"
        nulls: true

Yaml

You can do similar shenaniganz with Yaml as well thanks to Symfony\ExpressionLanguage

services:
    App\Mailer:
        arguments: ["@=service('App\\\\Mail\\\\MailerConfiguration').getMailerMethod()"]

If you want to see real-life example, I tried it once. But went quickly back because I could not remember what exactly that means and how it work.

How is the Ecosystem Support?

This is the most important question when it comes to open-source code. You can create your own natural language, that is smart, easy to learn, context aware and super fast. But what if 1.39 billion people speaks English already?

PHPStorm Support

Neon

You can install Neon Plugin, that handles param and class autocomplete very nicely. It's enabled for every *.neon file by default.

Yaml

Yaml support is included in Symfony Plugin. It needs to by enabled per project. It works great, there is just one last thing I miss. It already completes services for Symfony 3.2- format:

services:
    some_name:
        class: AutocompletedClass

But since Symfony 3.3 there is short syntax for services:

services:
    ManuallyTypedService: ~

And it is missing autocomplete in time being. Do you want autocomplete for this case too? Upvote this issue or send PR in Java to the plugin.

Also Github lacks of Neon support.

Who is the Winner?

Which one to pick? It depends on what is important to you. If you use Nette and work in Czech company and Neon is weapon of choice for you - it's ok.

But what if you're making open source for the whole world?

Why are Standards so Important?

I was on a train trip in Hungary and I was thirsty. I went to classic food shop and pick first bottle with still water I saw. I wanted still water cause gas hurts me and wanted to drink a lot. And I'm drunk when it comes to water in summer.

At least I though I picked the right one until I opened it. In every single country I've been to so far, the blue is always still water. But not in Hungary!

As Chris says: "In Hungary the color code is reversed where blue means sparkling and red means flat." And there is even question on Tripadvisor on this topic.


For all the reasons above (thirsty-human-friendly-bottle-colors included), after looking at problem from various points of view and discussing with my Github and PHP friends, I came to conclusion that Yaml is better for me.

How to Migrate from Neon to YAML?

But EasyCodingStandard was running on Neon that was loaded by my few classes to Symfony Kernel, so how to migrate to Yaml?

Imports

-includes:
+imports:
-    - packages/EasyCodingStandard/config/psr2.neon
+    - { resource: 'packages/EasyCodingStandard/config/psr2.yml' }

-    - common/array.neon
-    - common/control-structures.neon
-    - common/docblock.neon
+    - { resource: 'common/*.yml' }

Lists

 services:
     # class should be Abstract or Final
-    - SlamCsFixer\FinalInternalClassFixer
+    SlamCsFixer\FinalInternalClassFixer: ~
     ArrayFixer: ~

Quoting parameters

 parameters:
     skip:
         SlevomatCodingStandard\Sniffs\TypeHints\TypeHintDeclarationSniff:
-            - *packages/CodingStandard/src/Sniffs/*/*Sniff.php
+            - '*packages/CodingStandard/src/Sniffs/*/*Sniff.php'

Multi-lines

-perex: '''
+perex: |
     Do you know `*.neon` format? It's config file
-format created in Czech Republic...
+    format created in Czech Republic...
-'''

And from *.yml to *.neon? Just revert - and + :).

To see what code exactly had to change:


Which format do you prefer and why? Do you have some other WTF examples or migration tips? Let me know in the comments!



Happy coding!




Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors. I'd really appreciate it!