links-notation 0.18.0 → 0.20.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 +91 -4
- package/README.ru.md +60 -4
- package/dist/index.js +476 -21
- package/index.d.ts +95 -0
- package/package.json +1 -1
- package/src/Link.js +4 -0
- package/src/Parser.js +8 -1
- package/src/StreamParser.js +284 -0
- package/src/comments.js +164 -0
- package/src/grammar.pegjs +7 -1
- package/src/index.js +2 -0
- package/src/parser-generated.js +152 -18
- package/tests/Comments.test.js +160 -0
- package/tests/ParseErrorPosition.test.js +15 -13
- package/tests/StreamParser.test.js +165 -0
package/README.md
CHANGED
|
@@ -147,6 +147,45 @@ const group = new LinksGroup(parsed);
|
|
|
147
147
|
console.log(group.format());
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
+
### Streaming Parser (for Large Messages)
|
|
151
|
+
|
|
152
|
+
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:
|
|
153
|
+
|
|
154
|
+
- Large files that don't fit in memory
|
|
155
|
+
- Network streaming (TCP/HTTP)
|
|
156
|
+
- Real-time processing of incoming data
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
import { StreamParser } from 'links-notation';
|
|
160
|
+
|
|
161
|
+
const parser = new StreamParser({ collect: false, maxBufferSize: 1024 * 1024 });
|
|
162
|
+
|
|
163
|
+
// Listen for parsed links
|
|
164
|
+
parser.on('link', (link) => {
|
|
165
|
+
console.log('Parsed link:', link.toString());
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Listen for errors with location information
|
|
169
|
+
parser.on('error', (error) => {
|
|
170
|
+
console.error(
|
|
171
|
+
`Error at line ${error.line}, col ${error.column}: ${error.message}`
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Feed data incrementally (e.g., from network chunks)
|
|
176
|
+
parser.write('papa (lovesMama: loves mama)\n');
|
|
177
|
+
parser.write('son lovesMama\n');
|
|
178
|
+
parser.write('daughter lovesMama\n');
|
|
179
|
+
|
|
180
|
+
// Finish the last record. Links are not retained when collection is disabled.
|
|
181
|
+
parser.end();
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`StreamParser.parse(chunks)` and `StreamParser.parseAsync(chunks)` expose native
|
|
185
|
+
sync and async iterables. The parser also provides `position()`, `drain()`,
|
|
186
|
+
`reset()`, and a maximum unresolved-record size. See the
|
|
187
|
+
[streaming parser example](../examples/js_streaming_parser.js).
|
|
188
|
+
|
|
150
189
|
### TypeScript Usage Examples
|
|
151
190
|
|
|
152
191
|
```typescript
|
|
@@ -252,6 +291,39 @@ const links = new Parser().parse(`value (
|
|
|
252
291
|
console.log(formatLinks(links)); // (value ((id 1) (label one)))
|
|
253
292
|
```
|
|
254
293
|
|
|
294
|
+
### Comments
|
|
295
|
+
|
|
296
|
+
A `#` hides the rest of the line it stands on, so a document can carry prose
|
|
297
|
+
about itself:
|
|
298
|
+
|
|
299
|
+
```lino
|
|
300
|
+
# the machines this deploys to
|
|
301
|
+
deploy: staging # only staging, for now
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Both comments are gone by the time the document is read, leaving the single
|
|
305
|
+
link `(deploy: staging)`. A `#` only opens a comment where a reference could
|
|
306
|
+
begin, so a `#` inside a token (`issue#1047`) and a `#` inside a delimited
|
|
307
|
+
reference (`"#"`) stay ordinary characters.
|
|
308
|
+
|
|
309
|
+
A formatter keeps the same rule from the other side: a reference that begins
|
|
310
|
+
with a `#` is written quoted (`'#tag'`), so a document it writes reads back as
|
|
311
|
+
itself.
|
|
312
|
+
|
|
313
|
+
Comments are on by default, and a parser can be told to read `#` as an ordinary
|
|
314
|
+
character again, for documents written before comments existed:
|
|
315
|
+
|
|
316
|
+
```javascript
|
|
317
|
+
import { Parser, formatLinks } from 'links-notation';
|
|
318
|
+
|
|
319
|
+
const document =
|
|
320
|
+
'# the machines this deploys to\ndeploy: staging # only staging, for now\n';
|
|
321
|
+
console.log(formatLinks(new Parser().parse(document))); // (deploy: staging)
|
|
322
|
+
|
|
323
|
+
const plain = new Parser({ comments: false });
|
|
324
|
+
console.log(formatLinks(plain.parse('# a b\n'))); // (# a b)
|
|
325
|
+
```
|
|
326
|
+
|
|
255
327
|
## API Reference
|
|
256
328
|
|
|
257
329
|
### Classes
|
|
@@ -260,6 +332,8 @@ console.log(formatLinks(links)); // (value ((id 1) (label one)))
|
|
|
260
332
|
|
|
261
333
|
Main parser class for converting strings to links.
|
|
262
334
|
|
|
335
|
+
- `constructor(options)` - Create a parser; `options.comments` set to `false`
|
|
336
|
+
reads `#` as an ordinary character instead of the start of a comment
|
|
263
337
|
- `initialize()` - Initialize the parser (async)
|
|
264
338
|
- `parse(input)` - Parse a Lino string and return links
|
|
265
339
|
|
|
@@ -279,6 +353,19 @@ Container for grouping related links.
|
|
|
279
353
|
- `constructor(links)` - Create a new group
|
|
280
354
|
- `format()` - Format the group as a string
|
|
281
355
|
|
|
356
|
+
#### `StreamParser`
|
|
357
|
+
|
|
358
|
+
EventEmitter-based streaming parser for incremental parsing.
|
|
359
|
+
|
|
360
|
+
- `constructor(options)` - Create a new streaming parser
|
|
361
|
+
- `options.maxInputSize` - Maximum input size in bytes (default: 10MB)
|
|
362
|
+
- `options.maxDepth` - Maximum nesting depth (default: 1000)
|
|
363
|
+
- `write(chunk)` - Feed a chunk of data to the parser
|
|
364
|
+
- `end()` - Finish parsing and return all parsed links
|
|
365
|
+
- `position()` - Get current parsing position (line, column, offset)
|
|
366
|
+
- Event: `'link'` - Emitted when a link is parsed (callback receives Link object)
|
|
367
|
+
- Event: `'error'` - Emitted on parse error (callback receives Error with line/column info)
|
|
368
|
+
|
|
282
369
|
#### `ParseError`
|
|
283
370
|
|
|
284
371
|
Thrown by `parse(input)` when the document does not parse. The message says
|
|
@@ -288,7 +375,7 @@ where the document stopped making sense and quotes the offending line:
|
|
|
288
375
|
import { Parser, ParseError } from 'links-notation';
|
|
289
376
|
|
|
290
377
|
try {
|
|
291
|
-
new Parser().parse('
|
|
378
|
+
new Parser().parse('ci_gate x\nstage: rust: nextest\n');
|
|
292
379
|
} catch (error) {
|
|
293
380
|
console.error(error.message);
|
|
294
381
|
if (error instanceof ParseError) {
|
|
@@ -298,9 +385,9 @@ try {
|
|
|
298
385
|
```
|
|
299
386
|
|
|
300
387
|
```text
|
|
301
|
-
Syntax error at line 2, column
|
|
302
|
-
2 |
|
|
303
|
-
|
|
|
388
|
+
Syntax error at line 2, column 12: Expected "(", [ \t], [\r\n], or [^ \t\n\r(:)] but ":" found.
|
|
389
|
+
2 | stage: rust: nextest
|
|
390
|
+
| ^
|
|
304
391
|
```
|
|
305
392
|
|
|
306
393
|
- `offset` - Offset of the offending position from the start of the document
|
package/README.ru.md
CHANGED
|
@@ -105,6 +105,27 @@ const group = new LinksGroup(parsed);
|
|
|
105
105
|
console.log(group.format());
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
### Потоковый парсер
|
|
109
|
+
|
|
110
|
+
`StreamParser` принимает произвольные порции данных и отправляет события только
|
|
111
|
+
для завершённых связей верхнего уровня. Отключите накопление для обработки с
|
|
112
|
+
ограниченной памятью.
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
import { StreamParser } from 'links-notation';
|
|
116
|
+
|
|
117
|
+
const stream = new StreamParser({ collect: false, maxBufferSize: 1024 * 1024 });
|
|
118
|
+
stream.on('link', (link) => console.log(link.toString()));
|
|
119
|
+
stream.on('error', (error) => console.error(error));
|
|
120
|
+
stream.write('профиль:\n имя Ада\n');
|
|
121
|
+
stream.end('следующая связь');
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`StreamParser.parse(chunks)` и `StreamParser.parseAsync(chunks)` предоставляют
|
|
125
|
+
нативные синхронные и асинхронные итераторы. Также доступны `position()`,
|
|
126
|
+
`drain()`, `reset()` и ограничение размера незавершённой записи. См.
|
|
127
|
+
[исполняемый пример](../examples/js_streaming_parser.js).
|
|
128
|
+
|
|
108
129
|
## Примеры синтаксиса
|
|
109
130
|
|
|
110
131
|
### Дуплеты (2-кортежи)
|
|
@@ -171,6 +192,39 @@ const links = new Parser().parse(`value (
|
|
|
171
192
|
console.log(formatLinks(links)); // (value ((id 1) (label one)))
|
|
172
193
|
```
|
|
173
194
|
|
|
195
|
+
### Комментарии
|
|
196
|
+
|
|
197
|
+
`#` скрывает остаток строки, на которой стоит, поэтому документ может нести
|
|
198
|
+
пояснения о самом себе:
|
|
199
|
+
|
|
200
|
+
```lino
|
|
201
|
+
# машины, на которые идёт выкладка
|
|
202
|
+
deploy: staging # пока только staging
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
К моменту чтения документа обоих комментариев уже нет, остаётся одна связь
|
|
206
|
+
`(deploy: staging)`. `#` открывает комментарий только там, где могла бы
|
|
207
|
+
начаться ссылка, поэтому `#` внутри токена (`issue#1047`) и `#` внутри ссылки
|
|
208
|
+
в кавычках (`"#"`) остаются обычными символами.
|
|
209
|
+
|
|
210
|
+
Форматтер соблюдает то же правило с другой стороны: ссылка, начинающаяся с `#`,
|
|
211
|
+
записывается в кавычках (`'#tag'`), поэтому написанный им документ читается
|
|
212
|
+
обратно как он сам.
|
|
213
|
+
|
|
214
|
+
Комментарии включены по умолчанию, а парсеру можно велеть снова читать `#` как
|
|
215
|
+
обычный символ - для документов, написанных до появления комментариев:
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
import { Parser, formatLinks } from 'links-notation';
|
|
219
|
+
|
|
220
|
+
const document =
|
|
221
|
+
'# машины, на которые идёт выкладка\ndeploy: staging # пока только staging\n';
|
|
222
|
+
console.log(formatLinks(new Parser().parse(document))); // (deploy: staging)
|
|
223
|
+
|
|
224
|
+
const plain = new Parser({ comments: false });
|
|
225
|
+
console.log(formatLinks(plain.parse('# a b\n'))); // (# a b)
|
|
226
|
+
```
|
|
227
|
+
|
|
174
228
|
## Справочник API
|
|
175
229
|
|
|
176
230
|
### Классы
|
|
@@ -179,6 +233,8 @@ console.log(formatLinks(links)); // (value ((id 1) (label one)))
|
|
|
179
233
|
|
|
180
234
|
Основной класс парсера для преобразования строк в связи.
|
|
181
235
|
|
|
236
|
+
- `constructor(options)` - Создать парсер; `options.comments` со значением
|
|
237
|
+
`false` читает `#` как обычный символ, а не как начало комментария
|
|
182
238
|
- `initialize()` - Инициализация парсера (асинхронно)
|
|
183
239
|
- `parse(input)` - Парсинг строки Lino и возвращение связей
|
|
184
240
|
|
|
@@ -207,7 +263,7 @@ console.log(formatLinks(links)); // (value ((id 1) (label one)))
|
|
|
207
263
|
import { Parser, ParseError } from 'links-notation';
|
|
208
264
|
|
|
209
265
|
try {
|
|
210
|
-
new Parser().parse('
|
|
266
|
+
new Parser().parse('ci_gate x\nstage: rust: nextest\n');
|
|
211
267
|
} catch (error) {
|
|
212
268
|
console.error(error.message);
|
|
213
269
|
if (error instanceof ParseError) {
|
|
@@ -217,9 +273,9 @@ try {
|
|
|
217
273
|
```
|
|
218
274
|
|
|
219
275
|
```text
|
|
220
|
-
Syntax error at line 2, column
|
|
221
|
-
2 |
|
|
222
|
-
|
|
|
276
|
+
Syntax error at line 2, column 12: Expected "(", [ \t], [\r\n], or [^ \t\n\r(:)] but ":" found.
|
|
277
|
+
2 | stage: rust: nextest
|
|
278
|
+
| ^
|
|
223
279
|
```
|
|
224
280
|
|
|
225
281
|
- `offset` - Смещение сломанной позиции от начала документа
|