links-notation 0.27.0 → 0.28.0
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 +60 -1
- package/README.ru.md +45 -0
- package/dist/index.js +401 -97
- package/index.d.ts +103 -1
- package/package.json +2 -2
- package/src/Cst.js +263 -0
- package/src/Emitter.js +134 -0
- package/src/Link.js +41 -1
- package/src/Parser.js +49 -10
- package/src/StreamParser.js +2 -2
- package/src/grammar.pegjs +15 -4
- package/src/index.js +6 -1
- package/src/parser-generated.js +73 -53
- package/src/references.js +18 -0
- package/tests/BrowserBundle.test.js +187 -0
- package/tests/Cst.test.js +109 -0
- package/tests/SharedSyntaxParity.test.js +47 -0
- package/tests/SyntaxMetadata.test.js +102 -0
package/README.md
CHANGED
|
@@ -27,6 +27,14 @@ bun add links-notation
|
|
|
27
27
|
import { Parser, Link } from 'npm:links-notation@^0.6.0';
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
#### In browsers
|
|
31
|
+
|
|
32
|
+
The package has no runtime dependencies and imports no Node.js built-in
|
|
33
|
+
modules, so bundlers need no polyfills. For example, esbuild bundles it with
|
|
34
|
+
`esbuild entry.js --bundle --platform=browser`. Before 0.27.1, `StreamParser`
|
|
35
|
+
imported Node's `events` module, and browser bundles needed the `events`
|
|
36
|
+
package installed as a polyfill.
|
|
37
|
+
|
|
30
38
|
### Local Development Setup
|
|
31
39
|
|
|
32
40
|
For contributors working on the source code:
|
|
@@ -226,6 +234,47 @@ call it on already decoded `Link.id` values.
|
|
|
226
234
|
|
|
227
235
|
See the [Q&A document example](../examples/js_indented_document.js).
|
|
228
236
|
|
|
237
|
+
### How a Document Was Written (CST)
|
|
238
|
+
|
|
239
|
+
Parsing keeps how every ID was written. Quoting never changes a reference:
|
|
240
|
+
`1` and `'1'` are the same reference, so equality, formatting and JSON stay as
|
|
241
|
+
they were. Each parsed link also carries `rawId`, the ID exactly as written,
|
|
242
|
+
and `quote`, the delimiter it was written between:
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
import { Parser } from 'links-notation';
|
|
246
|
+
|
|
247
|
+
const [link] = new Parser().parse("(t 1 '1')");
|
|
248
|
+
const [, bare, quoted] = link.values;
|
|
249
|
+
bare.equals(quoted); // true: the same reference
|
|
250
|
+
[bare.rawId, bare.quote]; // ['1', null]
|
|
251
|
+
[quoted.rawId, quoted.quote]; // ["'1'", "'"]
|
|
252
|
+
link.format(); // '(t 1 1)'
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
`rawId` is `null` for links without an ID, links built in code, and links
|
|
256
|
+
made by indentation path combination. Use `new Parser({ syntax: false })` (AST
|
|
257
|
+
mode) to leave it out.
|
|
258
|
+
|
|
259
|
+
`parseCst(input)` returns the lossless concrete syntax tree. Every character,
|
|
260
|
+
including comments, blank lines, indentation, quotes and line endings, belongs
|
|
261
|
+
to exactly one token, so the original text is always recovered:
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
const cst = new Parser().parseCst("(t 1 '1') # note\n");
|
|
265
|
+
cst.toString(); // "(t 1 '1') # note\n"
|
|
266
|
+
cst.tokens().map((token) => [token.kind, token.text]);
|
|
267
|
+
// [['open_paren', '('], ['reference', 't'], ['whitespace', ' '], ...]
|
|
268
|
+
cst.toSExpression();
|
|
269
|
+
// (document (line (group open_paren:"(" (line reference:"t" ...) close_paren:")") whitespace:" " comment:"# note" newline:"\n"))
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
A `document` node holds `line` nodes. A line holds its tokens up to and
|
|
273
|
+
including its line ending. A `group` node holds `(`, the lines inside it, and
|
|
274
|
+
`)`. Reference tokens carry `value` (what the reference means) and `quote`.
|
|
275
|
+
`parseCst` refuses exactly what `parse` refuses. See
|
|
276
|
+
[the issue 364 case study](../docs/case-studies/issue-364/README.md).
|
|
277
|
+
|
|
229
278
|
### Streaming Parser (for Large Messages)
|
|
230
279
|
|
|
231
280
|
The `StreamParser` allows you to parse Links Notation incrementally, processing data as it arrives without loading the entire message into memory. This is ideal for:
|
|
@@ -421,6 +470,9 @@ Main parser class for converting strings to links.
|
|
|
421
470
|
- `initialize()` - Initialize the parser (async)
|
|
422
471
|
- `parse(input)` - Parse a Lino string and return links
|
|
423
472
|
- `parseGroups(input)` - Read an indentation tree as `LinksGroup` instances
|
|
473
|
+
- `parseCst(input)` - Read the lossless concrete syntax tree (`CstNode`)
|
|
474
|
+
- `options.syntax` - If `false` (AST mode), parsed links leave `rawId` null
|
|
475
|
+
(default: `true`)
|
|
424
476
|
|
|
425
477
|
#### `Link`
|
|
426
478
|
|
|
@@ -430,6 +482,9 @@ Represents a single link with ID and values.
|
|
|
430
482
|
- `toString()` - Convert link to string format
|
|
431
483
|
- `id` - Link identifier
|
|
432
484
|
- `values` - Array of child values/links
|
|
485
|
+
- `rawId` - The ID exactly as the parsed document wrote it, or `null`; ignored
|
|
486
|
+
by `equals`, `format` and JSON
|
|
487
|
+
- `quote` - `'`, `"` or `` ` `` when `rawId` is quoted, otherwise `null`
|
|
433
488
|
- `escapeReference(reference, options)` - Quote a reference; `minimal: true`
|
|
434
489
|
allows ordinary prose on a text document line
|
|
435
490
|
- `unescapeReference(reference)` - Decode a complete serialized reference
|
|
@@ -443,7 +498,11 @@ Container for grouping related links.
|
|
|
443
498
|
|
|
444
499
|
#### `StreamParser`
|
|
445
500
|
|
|
446
|
-
|
|
501
|
+
Event-emitting streaming parser for incremental parsing. Its built-in emitter
|
|
502
|
+
has the Node.js `EventEmitter` listener methods (`on`, `once`, `off`,
|
|
503
|
+
`addListener`, `removeListener`, `prependListener`, `prependOnceListener`,
|
|
504
|
+
`removeAllListeners`, `emit`, `listeners`, `listenerCount`, `eventNames`) and
|
|
505
|
+
works in browsers without a polyfill. It is not an `instanceof EventEmitter`.
|
|
447
506
|
|
|
448
507
|
- `constructor(options)` - Create a new streaming parser
|
|
449
508
|
- `options.maxInputSize` - Maximum input size in bytes (default: 10MB)
|
package/README.ru.md
CHANGED
|
@@ -153,6 +153,38 @@ const group = new LinksGroup(parsed);
|
|
|
153
153
|
console.log(group.format());
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
+
### Как документ был записан (CST)
|
|
157
|
+
|
|
158
|
+
Парсер сохраняет, как была записана каждая ссылка. Кавычки не меняют ссылку:
|
|
159
|
+
`1` и `'1'` - одна и та же ссылка, поэтому сравнение, форматирование и JSON
|
|
160
|
+
остаются прежними. Каждая разобранная связь хранит `rawId` - ID в точности
|
|
161
|
+
так, как он записан, и `quote` - кавычку, в которую он заключён:
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
import { Parser } from 'links-notation';
|
|
165
|
+
|
|
166
|
+
const [link] = new Parser().parse("(t 1 '1')");
|
|
167
|
+
const [, bare, quoted] = link.values;
|
|
168
|
+
bare.equals(quoted); // true: это одна ссылка
|
|
169
|
+
[bare.rawId, bare.quote]; // ['1', null]
|
|
170
|
+
[quoted.rawId, quoted.quote]; // ["'1'", "'"]
|
|
171
|
+
link.format(); // '(t 1 1)'
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`rawId` равен `null` у связей без ID, у связей, созданных в коде, и у связей,
|
|
175
|
+
построенных объединением путей по отступам. `new Parser({ syntax: false })`
|
|
176
|
+
(режим AST) не сохраняет его.
|
|
177
|
+
|
|
178
|
+
`parseCst(input)` возвращает конкретное синтаксическое дерево без потерь:
|
|
179
|
+
каждый символ, включая комментарии, пустые строки, отступы, кавычки и
|
|
180
|
+
переводы строк, принадлежит ровно одному токену, поэтому исходный текст
|
|
181
|
+
всегда восстанавливается: `new Parser().parseCst(text).toString() === text`.
|
|
182
|
+
Узел `document` содержит узлы `line`; строка содержит свои токены вместе с
|
|
183
|
+
переводом строки; узел `group` содержит `(`, строки внутри и `)`. Токены
|
|
184
|
+
ссылок хранят `value` (что означает ссылка) и `quote`. `parseCst` отклоняет
|
|
185
|
+
ровно то, что отклоняет `parse`. Подробности - в
|
|
186
|
+
[разборе issue 364](../docs/case-studies/issue-364/README.md).
|
|
187
|
+
|
|
156
188
|
### Потоковый парсер
|
|
157
189
|
|
|
158
190
|
`StreamParser` принимает произвольные порции данных и отправляет события только
|
|
@@ -174,6 +206,13 @@ stream.end('следующая связь');
|
|
|
174
206
|
`drain()`, `reset()` и ограничение размера незавершённой записи. См.
|
|
175
207
|
[исполняемый пример](../examples/js_streaming_parser.js).
|
|
176
208
|
|
|
209
|
+
Пакет не импортирует встроенные модули Node.js, поэтому сборщикам для браузера
|
|
210
|
+
не нужны полифилы: например, `esbuild entry.js --bundle --platform=browser`.
|
|
211
|
+
Встроенный в `StreamParser` эмиттер поддерживает методы подписки
|
|
212
|
+
`EventEmitter` из Node.js (`on`, `once`, `off`, `removeListener`, `emit`,
|
|
213
|
+
`listenerCount` и другие). До версии 0.27.1 `StreamParser` импортировал модуль
|
|
214
|
+
`events`, и для браузерной сборки требовался пакет-полифил `events`.
|
|
215
|
+
|
|
177
216
|
## Примеры синтаксиса
|
|
178
217
|
|
|
179
218
|
### Дуплеты (2-кортежи)
|
|
@@ -291,6 +330,9 @@ console.log(formatLinks(plain.parse('# a b\n'))); // (# a b)
|
|
|
291
330
|
отклоняется с `ParseError`, а не разбирается рекурсивно, пока не кончится стек
|
|
292
331
|
- `initialize()` - Инициализация парсера (асинхронно)
|
|
293
332
|
- `parse(input)` - Парсинг строки Lino и возвращение связей
|
|
333
|
+
- `parseCst(input)` - Конкретное синтаксическое дерево без потерь (`CstNode`)
|
|
334
|
+
- `options.syntax` - Со значением `false` (режим AST) связи не хранят `rawId`
|
|
335
|
+
(по умолчанию: `true`)
|
|
294
336
|
|
|
295
337
|
#### `Link`
|
|
296
338
|
|
|
@@ -300,6 +342,9 @@ console.log(formatLinks(plain.parse('# a b\n'))); // (# a b)
|
|
|
300
342
|
- `toString()` - Преобразование связи в строковый формат
|
|
301
343
|
- `id` - Идентификатор связи
|
|
302
344
|
- `values` - Массив дочерних значений/связей
|
|
345
|
+
- `rawId` - ID в точности так, как он записан в документе, или `null`;
|
|
346
|
+
`equals`, `format` и JSON его не учитывают
|
|
347
|
+
- `quote` - `'`, `"` или `` ` ``, если `rawId` в кавычках, иначе `null`
|
|
303
348
|
|
|
304
349
|
#### `LinksGroup`
|
|
305
350
|
|