@nette/neon 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/readme.md ADDED
@@ -0,0 +1,243 @@
1
+ NEON for JavaScript
2
+ ===================
3
+
4
+ [![npm](https://img.shields.io/npm/v/@nette/neon.svg)](https://www.npmjs.com/package/@nette/neon)
5
+ [![Tests](https://github.com/nette/neon-js/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/nette/neon-js/actions)
6
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/nette/neon-js/blob/master/license.md)
7
+
8
+  <!---->
9
+
10
+ <h3>
11
+
12
+ ✅ A NEON parser that keeps [every comment and space](#the-tree-nodes-slots-tokens-trivia)<br>
13
+ ✅ [Edit a configuration file](#format-preserving-editing) and the diff is only your change<br>
14
+ ✅ [`neon-lint`](#for-editors-and-ai-agents) for editors, CI and AI agents<br>
15
+ ✅ [No dependencies](#installation), runs in Node and in the browser
16
+
17
+ </h3>
18
+
19
+  <!---->
20
+
21
+ **NEON parser, encoder and lossless editor for JavaScript and TypeScript.** NEON is the
22
+ human-friendly configuration format of the Nette framework, a YAML alternative with entities.
23
+ This library parses it into a concrete syntax tree in which every character of the file has
24
+ its place, so printing the tree gives the file back byte for byte:
25
+
26
+ ```ts
27
+ const doc = parse(text);
28
+ doc.print() === text; // true, for any input NEON accepts
29
+ ```
30
+
31
+ That is what makes editing safe. Change a value, add a key, remove an item, and the rest of the
32
+ file stays as its author wrote it:
33
+
34
+ ```ts
35
+ doc.setValue(['database', 'host'], 'db.example.com');
36
+ ```
37
+
38
+ ```
39
+ - host: localhost # the server
40
+ + host: db.example.com # the server
41
+ ```
42
+
43
+ On that you build configuration editors and admin panels, installers that register an extension
44
+ in `config.neon`, migrations that rename a service, and AI agents that change configuration
45
+ without wrecking it.
46
+
47
+ The library comes from David Grudl, the author of [Nette](https://nette.org),
48
+ [Latte](https://latte.nette.org) and [Tracy](https://tracy.nette.org). NEON has been the
49
+ configuration format of Nette since 2011, read by every Nette application, and this
50
+ implementation follows the same specification as [nette/neon](https://github.com/nette/neon) for PHP.
51
+
52
+  <!---->
53
+
54
+ NEON in one minute
55
+ ==================
56
+
57
+ ```neon
58
+ # mappings and sequences, indented by tabs or spaces
59
+ database:
60
+ host: localhost
61
+ port: 3306
62
+
63
+ roles: [guest, member, admin] # inline arrays
64
+
65
+ # entities: a value with attributes, the way Nette writes services
66
+ mailer: App\Mailer(@smtp, timeout: 30)
67
+
68
+ note: '''
69
+ multiline strings
70
+ without escaping
71
+ '''
72
+ ```
73
+
74
+ JSON is a subset of NEON, except for a colon at the start of a line glued to its value
75
+ (`"a"` + new line + `:1`), which NEON reads as a literal. The format is described at
76
+ [ne-on.org](https://ne-on.org) and in the [manual](https://doc.nette.org/en/neon/format).
77
+
78
+ ▶ Runnable examples: [examples/edge-cases](examples/edge-cases/)
79
+
80
+  <!---->
81
+
82
+ Why NEON, if YAML exists
83
+ ========================
84
+
85
+ YAML is widespread and its libraries are mature. NEON did not start as its replacement but as the
86
+ configuration format of Nette, and it has three things YAML does not have or has differently:
87
+
88
+ - **entities**: `Column(type: int, nullable: true)` is a value, and the configuration of the DI
89
+ container of Nette lives on it;
90
+ - **tabs** for indentation;
91
+ - **a smaller language**: no anchors, tags, directives or multi-document streams, and no flow
92
+ and block styles with different meanings.
93
+
94
+ Both read JSON.
95
+
96
+  <!---->
97
+
98
+ Format-preserving editing
99
+ =========================
100
+
101
+ Most YAML libraries, like js-yaml, drop comments and formatting when they write a file; those
102
+ that keep them, like the `yaml` package, document where they cannot. Here it is an invariant, not
103
+ an effort: every edit changes the tokens it edits, and the four guarantees of the specification
104
+ (the file reads back as the same tree, with the expected value, with the change only where it was
105
+ made) are checked after every operation of a large corpus of edits.
106
+
107
+ ```ts
108
+ import { CommentPolicy, parse } from '@nette/neon';
109
+
110
+ const doc = parse(text);
111
+ doc.setValue(['database', 'port'], 3307); // 0x0CEA stays hexadecimal: 0x0CEB
112
+ doc.setValue(['database', 'debug'], false); // yes becomes no, not false
113
+ doc.setValue(['timeout'], 30); // the same value: no change at all
114
+ doc.setValue(['parameters', 'admin'], 'a@b.cz'); // a new key, indented like its siblings
115
+ doc.addItem(['services'], 'App\\OrderFacade'); // a new item of a list
116
+ doc.removeItem(['database', 'driver']); // with the comment that describes it
117
+ doc.removeItem(['mail'], { comments: CommentPolicy.MoveToNextToken });
118
+ ```
119
+
120
+ A missing key in the middle of a path is an error, so a typo does not create a new section.
121
+ Removing the last item of a collection leaves it empty (`services: []`), because in a
122
+ configuration empty and missing often mean different things; an item marked `nullable` loses its
123
+ value instead.
124
+
125
+ ▶ Runnable examples: [examples/editing](examples/editing/), [examples/config-editor](examples/config-editor/)
126
+
127
+  <!---->
128
+
129
+ Installation
130
+ ============
131
+
132
+ ```shell
133
+ npm install @nette/neon
134
+ ```
135
+
136
+ ES module, TypeScript types included, Node 22 or newer, or any current browser. No dependencies.
137
+ The core uses no Node API; only the `neon-lint` command does.
138
+
139
+  <!---->
140
+
141
+ The tree: nodes, slots, tokens, trivia
142
+ ======================================
143
+
144
+ ```ts
145
+ const item = doc.findItem(['database', 'user']);
146
+ item.getValue(); // 'root'
147
+ item.getTrailingComments(); // the comment on its line
148
+ item.value.getFirstToken().text; // the text exactly as written
149
+ item.getPosition(); // { line, column, offset }, computed from the current tree
150
+ ```
151
+
152
+ Eight node classes (`DocumentNode`, `BlockArrayNode`, `InlineArrayNode`, `ArrayItemNode`,
153
+ `EntityNode`, `EntityChainNode`, `StringNode`, `LiteralNode`) with named slots, tokens with their
154
+ trivia (whitespace, line endings, comments), `find()`, `findAncestor()`, siblings, and
155
+ `Traverser` for a walk with replacements.
156
+
157
+ ▶ Runnable examples: [examples/tree](examples/tree/)
158
+
159
+  <!---->
160
+
161
+ Decoding and encoding
162
+ =====================
163
+
164
+ ```ts
165
+ import { decode, encode } from '@nette/neon';
166
+
167
+ decode('a: [1, 2]'); // { a: [1, 2] }
168
+ encode({ a: [1, 2] }); // '{a: [1, 2]}'
169
+ encode({ a: [1, 2] }, true); // 'a:\n\t- 1\n\t- 2\n\n'
170
+ encode({ a: [1, 2] }, (_, path) => !path.length); // 'a: [1, 2]\n', blocks for the first level only
171
+ encode(config, (value) => !Array.isArray(value)); // lists on one line
172
+ ```
173
+
174
+ | NEON | JavaScript |
175
+ |---|---|
176
+ | `null`, `true`, `yes` ... | `null`, `boolean` |
177
+ | integer | `number`, beyond 2^53 a `bigint` |
178
+ | float | `number` |
179
+ | string | `string` |
180
+ | date | `NeonDate` (components and offset as written; `toDate(zone)` for an instant) |
181
+ | entity, chain | `Entity` |
182
+ | list | `Array` |
183
+ | map | plain object with own properties, so `__proto__` is just a key |
184
+
185
+ Two differences from PHP follow from JavaScript: an integral float like `1.0` is a `number` like
186
+ `1` and is written as `1`, and a plain object orders integer-like keys first (the tree keeps the
187
+ order of the file).
188
+
189
+ ▶ Runnable examples: [examples/parsing](examples/parsing/), [examples/encoding](examples/encoding/)
190
+
191
+  <!---->
192
+
193
+ One format, one specification
194
+ =============================
195
+
196
+ The format, the value model, the tree and the semantics of editing are written down in a
197
+ language-neutral [specification](https://github.com/nette/neon-specification) with a conformance corpus,
198
+ and every implementation runs that corpus in its tests. The values and the error messages were
199
+ checked against nette/neon for PHP over 95,000 real-world files. The corpus is public; if you write
200
+ an implementation of NEON for another language, use it.
201
+
202
+  <!---->
203
+
204
+ For editors and AI agents
205
+ =========================
206
+
207
+ ```shell
208
+ npx neon-lint config/
209
+ ```
210
+
211
+ ```
212
+ config/local.neon:3:2: Duplicated key 'user'
213
+ ```
214
+
215
+ One line per finding, the exit code as the verdict, `--json` for tools.
216
+ Editor plugins exist for PhpStorm, VS Code, Sublime Text, Vim and Emacs.
217
+
218
+ For **AI agents**, a short hook gives the agent an error right after it saves a broken `.neon`
219
+ file, so it fixes it before it goes on. The hook runs after the edit; it does not
220
+ prevent a broken save, but it makes sure it does not go unnoticed. See
221
+ [docs/skills/agents.md](docs/skills/agents.md).
222
+
223
+ ▶ Runnable examples: [examples/linting](examples/linting/)
224
+
225
+  <!---->
226
+
227
+ Limits
228
+ ======
229
+
230
+ - No formatter: the library keeps your formatting, it does not impose one.
231
+ - No schema or validation of values.
232
+ - No error recovery: an invalid file is reported, not partially parsed.
233
+ - Positions are computed on request, from the current tree.
234
+
235
+  <!---->
236
+
237
+ Documentation and credits
238
+ =========================
239
+
240
+ The [examples](examples/) are the documentation of the API, each chapter with the real output of
241
+ its programs. The format itself is documented in the [Nette manual](https://doc.nette.org/en/neon).
242
+
243
+ Released under the [MIT license](license.md).
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.