@faubulous/mentor-rdf-serializers 1.0.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.
Files changed (82) hide show
  1. package/README.md +582 -0
  2. package/dist/base-serializer.d.ts +63 -0
  3. package/dist/base-serializer.d.ts.map +1 -0
  4. package/dist/base-serializer.js +144 -0
  5. package/dist/base-serializer.js.map +1 -0
  6. package/dist/base-token-formatter.d.ts +225 -0
  7. package/dist/base-token-formatter.d.ts.map +1 -0
  8. package/dist/base-token-formatter.js +521 -0
  9. package/dist/base-token-formatter.js.map +1 -0
  10. package/dist/index.d.ts +20 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +36 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/jsonld/serializer.d.ts +99 -0
  15. package/dist/jsonld/serializer.d.ts.map +1 -0
  16. package/dist/jsonld/serializer.js +282 -0
  17. package/dist/jsonld/serializer.js.map +1 -0
  18. package/dist/n3/formatter.d.ts +105 -0
  19. package/dist/n3/formatter.d.ts.map +1 -0
  20. package/dist/n3/formatter.js +444 -0
  21. package/dist/n3/formatter.js.map +1 -0
  22. package/dist/n3/serializer.d.ts +103 -0
  23. package/dist/n3/serializer.d.ts.map +1 -0
  24. package/dist/n3/serializer.js +134 -0
  25. package/dist/n3/serializer.js.map +1 -0
  26. package/dist/nquads/formatter.d.ts +44 -0
  27. package/dist/nquads/formatter.d.ts.map +1 -0
  28. package/dist/nquads/formatter.js +116 -0
  29. package/dist/nquads/formatter.js.map +1 -0
  30. package/dist/nquads/serializer.d.ts +38 -0
  31. package/dist/nquads/serializer.d.ts.map +1 -0
  32. package/dist/nquads/serializer.js +70 -0
  33. package/dist/nquads/serializer.js.map +1 -0
  34. package/dist/ntriples/formatter.d.ts +44 -0
  35. package/dist/ntriples/formatter.d.ts.map +1 -0
  36. package/dist/ntriples/formatter.js +116 -0
  37. package/dist/ntriples/formatter.js.map +1 -0
  38. package/dist/ntriples/serializer.d.ts +38 -0
  39. package/dist/ntriples/serializer.d.ts.map +1 -0
  40. package/dist/ntriples/serializer.js +79 -0
  41. package/dist/ntriples/serializer.js.map +1 -0
  42. package/dist/sorting/index.d.ts +5 -0
  43. package/dist/sorting/index.d.ts.map +1 -0
  44. package/dist/sorting/index.js +5 -0
  45. package/dist/sorting/index.js.map +1 -0
  46. package/dist/sorting/strategies.d.ts +46 -0
  47. package/dist/sorting/strategies.d.ts.map +1 -0
  48. package/dist/sorting/strategies.js +259 -0
  49. package/dist/sorting/strategies.js.map +1 -0
  50. package/dist/sparql/formatter.d.ts +103 -0
  51. package/dist/sparql/formatter.d.ts.map +1 -0
  52. package/dist/sparql/formatter.js +764 -0
  53. package/dist/sparql/formatter.js.map +1 -0
  54. package/dist/token-serializer.d.ts +96 -0
  55. package/dist/token-serializer.d.ts.map +1 -0
  56. package/dist/token-serializer.js +456 -0
  57. package/dist/token-serializer.js.map +1 -0
  58. package/dist/trig/formatter.d.ts +99 -0
  59. package/dist/trig/formatter.d.ts.map +1 -0
  60. package/dist/trig/formatter.js +418 -0
  61. package/dist/trig/formatter.js.map +1 -0
  62. package/dist/trig/serializer.d.ts +39 -0
  63. package/dist/trig/serializer.d.ts.map +1 -0
  64. package/dist/trig/serializer.js +170 -0
  65. package/dist/trig/serializer.js.map +1 -0
  66. package/dist/turtle/formatter.d.ts +56 -0
  67. package/dist/turtle/formatter.d.ts.map +1 -0
  68. package/dist/turtle/formatter.js +325 -0
  69. package/dist/turtle/formatter.js.map +1 -0
  70. package/dist/turtle/serializer.d.ts +87 -0
  71. package/dist/turtle/serializer.d.ts.map +1 -0
  72. package/dist/turtle/serializer.js +343 -0
  73. package/dist/turtle/serializer.js.map +1 -0
  74. package/dist/types.d.ts +323 -0
  75. package/dist/types.d.ts.map +1 -0
  76. package/dist/types.js +14 -0
  77. package/dist/types.js.map +1 -0
  78. package/dist/utils.d.ts +157 -0
  79. package/dist/utils.d.ts.map +1 -0
  80. package/dist/utils.js +446 -0
  81. package/dist/utils.js.map +1 -0
  82. package/package.json +73 -0
package/README.md ADDED
@@ -0,0 +1,582 @@
1
+ # @faubulous/mentor-rdf-serializers
2
+
3
+ A comprehensive RDF serialization library for TypeScript, designed as the counterpart to [@faubulous/mentor-rdf-parsers](https://github.com/faubulous/mentor-rdf-parsers). Optimized for IDE use cases such as code formatting and partial serialization.
4
+
5
+ ## Features
6
+
7
+ - **Multiple Formats**: N-Triples, N-Quads, Turtle, TriG, N3, JSON-LD
8
+ - **SPARQL Formatting**: Format SPARQL queries and updates with comment preservation
9
+ - **RDF 1.2 Support**: Full support for RDF 1.2 features including:
10
+ - Triple Terms (`<<( s p o )>>`)
11
+ - Reified Triples (`<< s p o >>`)
12
+ - Annotations (`{| p o |}`)
13
+ - Language direction (`@en--ltr`, `@ar--rtl`)
14
+ - **Advanced Formatting Options**: Control line width, alignment, blank node style, and more
15
+ - **Comment Preservation**: Preserve comments when reformatting source files
16
+ - **Token-based Serialization**: Serialize directly from parser tokens, preserving blank node IDs
17
+ - **Sorting Strategies**: Pluggable sorting with built-in alphabetical and priority-based strategies
18
+ - **IDE Integration**: Designed for code formatting and partial document serialization
19
+ - **Prefix Handling**: Automatic prefix compaction and expansion
20
+ - **Configurable Output**: Pretty printing, sorting, grouping options
21
+
22
+ ## Architecture
23
+
24
+ The `mentor-rdf-serializers` package is designed to work seamlessly with `mentor-rdf-parsers`, forming a complete round-trip pipeline for RDF processing in IDEs and editors.
25
+
26
+ ```mermaid
27
+ flowchart LR
28
+ subgraph Source
29
+ A[RDF text (Turtle, TriG, ...)]
30
+ B[SPARQL text]
31
+ C[RDF/JS quads]
32
+ end
33
+
34
+ subgraph mentor-rdf-parsers
35
+ P1[Parser]
36
+ T1[Tokens]
37
+ Q1[Quads]
38
+
39
+ A --> P1
40
+ P1 --> T1
41
+ P1 --> Q1
42
+
43
+ B --> L2[SparqlLexer] --> T2[SPARQL tokens]
44
+ end
45
+
46
+ subgraph mentor-rdf-serializers
47
+ S1[Quad serializers\n(Turtle, N-Triples, ...)]
48
+ TS[TokenSerializer]
49
+ SF[SparqlFormatter]
50
+ end
51
+
52
+ subgraph Output
53
+ O1[Serialized / formatted RDF]
54
+ O2[Formatted SPARQL]
55
+ end
56
+
57
+ C --> S1 --> O1
58
+ Q1 --> S1
59
+ T1 --> TS --> O1
60
+ T2 --> SF --> O2
61
+
62
+ style mentor-rdf-parsers fill:#e1f5fe
63
+ style mentor-rdf-serializers fill:#fff3e0
64
+ ```
65
+
66
+ ## Installation
67
+
68
+ ```bash
69
+ npm install @faubulous/mentor-rdf-serializers
70
+ ```
71
+
72
+ ## Quick Start
73
+
74
+ ```typescript
75
+ import { TurtleSerializer } from '@faubulous/mentor-rdf-serializers';
76
+ import DataFactory from '@rdfjs/data-model';
77
+
78
+ const serializer = new TurtleSerializer();
79
+
80
+ const quads = [
81
+ DataFactory.quad(
82
+ DataFactory.namedNode('http://example.org/subject'),
83
+ DataFactory.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
84
+ DataFactory.namedNode('http://example.org/Class')
85
+ ),
86
+ DataFactory.quad(
87
+ DataFactory.namedNode('http://example.org/subject'),
88
+ DataFactory.namedNode('http://example.org/name'),
89
+ DataFactory.literal('Example', 'en')
90
+ )
91
+ ];
92
+
93
+ const turtle = serializer.serialize(quads, {
94
+ prefixes: {
95
+ 'ex': 'http://example.org/',
96
+ 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
97
+ }
98
+ });
99
+
100
+ console.log(turtle);
101
+ // @prefix ex: <http://example.org/> .
102
+ // @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
103
+ //
104
+ // ex:subject a ex:Class ;
105
+ // ex:name "Example"@en .
106
+ ```
107
+
108
+ ## Serializers
109
+
110
+ ### N-Triples
111
+
112
+ ```typescript
113
+ import { NTriplesSerializer } from '@faubulous/mentor-rdf-serializers';
114
+
115
+ const serializer = new NTriplesSerializer();
116
+ const output = serializer.serialize(quads, { sort: true });
117
+ ```
118
+
119
+ ### N-Quads
120
+
121
+ ```typescript
122
+ import { NQuadsSerializer } from '@faubulous/mentor-rdf-serializers';
123
+
124
+ const serializer = new NQuadsSerializer();
125
+ const output = serializer.serialize(quads);
126
+ ```
127
+
128
+ ### Turtle
129
+
130
+ ```typescript
131
+ import { TurtleSerializer } from '@faubulous/mentor-rdf-serializers';
132
+
133
+ const serializer = new TurtleSerializer();
134
+ const output = serializer.serialize(quads, {
135
+ prefixes: { 'ex': 'http://example.org/' },
136
+ baseIri: 'http://example.org/',
137
+ groupBySubject: true,
138
+ sort: true
139
+ });
140
+ ```
141
+
142
+ ### TriG
143
+
144
+ ```typescript
145
+ import { TriGSerializer } from '@faubulous/mentor-rdf-serializers';
146
+
147
+ const serializer = new TriGSerializer();
148
+ const output = serializer.serialize(quadsWithGraphs, {
149
+ prefixes: { 'ex': 'http://example.org/' }
150
+ });
151
+ ```
152
+
153
+ ### N3
154
+
155
+ ```typescript
156
+ import { N3Serializer } from '@faubulous/mentor-rdf-serializers';
157
+
158
+ const serializer = new N3Serializer();
159
+ const output = serializer.serialize(quads); // Supports formulas and implications
160
+ ```
161
+
162
+ ### JSON-LD
163
+
164
+ ```typescript
165
+ import { JsonLdSerializer } from '@faubulous/mentor-rdf-serializers';
166
+
167
+ const serializer = new JsonLdSerializer();
168
+ const output = serializer.serialize(quads, {
169
+ prefixes: { 'ex': 'http://example.org/' },
170
+ useTypeShorthand: true,
171
+ useIdShorthand: true,
172
+ compactArrays: true,
173
+ prettyPrint: true
174
+ });
175
+ ```
176
+
177
+ ## SPARQL Formatting
178
+
179
+ ```typescript
180
+ import { SparqlFormatter } from '@faubulous/mentor-rdf-serializers';
181
+
182
+ const formatter = new SparqlFormatter();
183
+
184
+ // Format a SELECT query
185
+ const selectResult = formatter.formatFromText(`
186
+ SELECT ?s ?p ?o WHERE { ?s ?p ?o . FILTER(?o > 10) }
187
+ `, {
188
+ uppercaseKeywords: true,
189
+ alignPatterns: true,
190
+ sameBraceLine: true,
191
+ separateClauses: true,
192
+ maxLineWidth: 80
193
+ });
194
+
195
+ console.log(selectResult.output);
196
+
197
+ // Format a SPARQL UPDATE (same API)
198
+ const updateResult = formatter.formatFromText(`
199
+ INSERT DATA { <http://example.org/s> <http://example.org/p> "value" }
200
+ `, {
201
+ indent: ' ',
202
+ uppercaseKeywords: true
203
+ });
204
+
205
+ console.log(updateResult.output);
206
+
207
+ // Comments are preserved
208
+ const withComments = formatter.formatFromText(`
209
+ # Find all people
210
+ SELECT ?person WHERE {
211
+ ?person a <http://example.org/Person> . # Match persons
212
+ }
213
+ `);
214
+
215
+ console.log(withComments.output); // Comments remain in the formatted output
216
+ ```
217
+
218
+ ## Token-based Serialization
219
+
220
+ For IDE integration, you can serialize directly from parser tokens, which preserves blank node IDs and comments from the source document.
221
+
222
+ ```typescript
223
+ import { TokenSerializer } from '@faubulous/mentor-rdf-serializers';
224
+ import { TurtleParser } from '@faubulous/mentor-rdf-parsers';
225
+
226
+ const parser = new TurtleParser();
227
+ const parseResult = parser.parse(sourceDocument);
228
+
229
+ const tokenSerializer = new TokenSerializer();
230
+
231
+ // Serialize all tokens
232
+ const output = tokenSerializer.serialize(parseResult.tokens, {
233
+ preserveBlankNodeIds: true,
234
+ preserveComments: true // Keeps comments in output
235
+ });
236
+
237
+ // Serialize only a specific range (for range formatting)
238
+ const rangeOutput = tokenSerializer.serializeRange(
239
+ parseResult.tokens,
240
+ startOffset,
241
+ endOffset,
242
+ { preserveComments: true }
243
+ );
244
+ ```
245
+
246
+ ## Serialization Options
247
+
248
+ ### Common Options
249
+
250
+ | Option | Type | Description |
251
+ |--------|------|-------------|
252
+ | `prefixes` | `Record<string, string>` | Prefix mappings for compacting IRIs |
253
+ | `baseIri` | `string` | Base IRI for relative references |
254
+ | `sort` | `boolean` | Sort output alphabetically |
255
+ | `prettyPrint` | `boolean` | Enable pretty formatting |
256
+
257
+ ### Turtle/TriG Options
258
+
259
+ | Option | Type | Default | Description |
260
+ |--------|------|---------|-------------|
261
+ | `groupBySubject` | `boolean` | `true` | Group triples by subject |
262
+ | `usePrefixedNames` | `boolean` | `true` | Use prefixed names where possible |
263
+ | `useShorthandTypes` | `boolean` | `true` | Use `a` for `rdf:type` |
264
+ | `useLongStrings` | `boolean` | `true` | Use `"""` for multiline strings |
265
+ | `useNumericShorthands` | `boolean` | `true` | Use numeric literals without quotes |
266
+
267
+ ### Formatting Options
268
+
269
+ These options control the visual layout of Turtle, TriG, and SPARQL output:
270
+
271
+ | Option | Type | Default | Description |
272
+ |--------|------|---------|-------------|
273
+ | `maxLineWidth` | `number` | `0` | Maximum line width before wrapping (0 = no wrapping) |
274
+ | `alignPredicates` | `boolean` | `false` | Align predicates in columns |
275
+ | `alignObjects` | `boolean` | `false` | Align objects in columns (requires `alignPredicates`) |
276
+ | `blankNodeStyle` | `'labeled' \| 'inline' \| 'auto'` | `'auto'` | How to format blank nodes |
277
+ | `objectListStyle` | `'single-line' \| 'multi-line' \| 'auto'` | `'auto'` | How to format multiple objects |
278
+ | `predicateListStyle` | `'single-line' \| 'multi-line' \| 'first-same-line'` | `'first-same-line'` | How to format predicate lists |
279
+ | `blankLinesBetweenSubjects` | `boolean` | `true` | Insert blank lines between subject blocks |
280
+
281
+ #### Blank Node Style
282
+
283
+ ```typescript
284
+ // 'labeled' - Always use labeled blank nodes
285
+ _:b0 ex:name "Alice" .
286
+ _:b0 ex:knows _:b1 .
287
+
288
+ // 'inline' - Use inline property lists where possible
289
+ [ ex:name "Alice" ; ex:knows [ ex:name "Bob" ] ] .
290
+
291
+ // 'auto' - Inline for single-reference blank nodes, labeled for multi-reference
292
+ ```
293
+
294
+ #### Object List Style
295
+
296
+ ```typescript
297
+ // 'single-line' - Objects on same line
298
+ ex:s ex:p "a", "b", "c" .
299
+
300
+ // 'multi-line' - Each object on its own line
301
+ ex:s ex:p "a",
302
+ "b",
303
+ "c" .
304
+
305
+ // 'auto' - Based on maxLineWidth
306
+ ```
307
+
308
+ #### Predicate List Style
309
+
310
+ ```typescript
311
+ // 'first-same-line' - First predicate with subject
312
+ ex:s a ex:Class ;
313
+ ex:name "Example" ;
314
+ ex:value 42 .
315
+
316
+ // 'multi-line' - All predicates on separate lines
317
+ ex:s
318
+ a ex:Class ;
319
+ ex:name "Example" ;
320
+ ex:value 42 .
321
+
322
+ // 'single-line' - All on one line (compact)
323
+ ex:s a ex:Class ; ex:name "Example" ; ex:value 42 .
324
+ ```
325
+
326
+ ### JSON-LD Options
327
+
328
+ | Option | Type | Default | Description |
329
+ |--------|------|---------|-------------|
330
+ | `useTypeShorthand` | `boolean` | `true` | Use `@type` instead of `rdf:type` |
331
+ | `useIdShorthand` | `boolean` | `true` | Use `@id` for IRI references |
332
+ | `compactArrays` | `boolean` | `true` | Unwrap single-element arrays |
333
+ | `embedContext` | `boolean` | `true` | Include `@context` in output |
334
+ | `jsonIndent` | `number` | `2` | Indentation for pretty printing |
335
+
336
+ ### SPARQL Options
337
+
338
+ | Option | Type | Default | Description |
339
+ |--------|------|---------|-------------|
340
+ | `uppercaseKeywords` | `boolean` | `true` | Uppercase SPARQL keywords |
341
+ | `lowercaseKeywords` | `boolean` | `false` | Lowercase SPARQL keywords |
342
+ | `alignPatterns` | `boolean` | `true` | Align WHERE clause patterns |
343
+ | `sameBraceLine` | `boolean` | `true` | Opening braces on same line |
344
+ | `separateClauses` | `boolean` | `true` | Blank lines between major clauses |
345
+ | `maxLineWidth` | `number` | `0` | Maximum line width before wrapping |
346
+ | `objectListStyle` | `string` | `'auto'` | How to format object lists in patterns |
347
+ | `predicateListStyle` | `string` | `'first-same-line'` | How to format predicate lists |
348
+ | `blankLinesBetweenSubjects` | `boolean` | `true` | Blank lines between subject blocks |
349
+
350
+ ### Token Serialization Options
351
+
352
+ | Option | Type | Default | Description |
353
+ |--------|------|---------|-------------|
354
+ | `preserveBlankNodeIds` | `boolean` | `true` | Preserve original blank node IDs |
355
+ | `preserveComments` | `boolean` | `true` | Preserve comments from source |
356
+
357
+ ## RDF 1.2 Features
358
+
359
+ ### Triple Terms
360
+
361
+ ```typescript
362
+ import { TurtleSerializer } from '@faubulous/mentor-rdf-serializers';
363
+ import type { TripleTerm, Rdf12Quad } from '@faubulous/mentor-rdf-serializers';
364
+
365
+ const tripleTerm: TripleTerm = {
366
+ termType: 'TripleTerm',
367
+ subject: { termType: 'NamedNode', value: 'http://example.org/s' },
368
+ predicate: { termType: 'NamedNode', value: 'http://example.org/p' },
369
+ object: { termType: 'Literal', value: 'value', language: '', datatype: { termType: 'NamedNode', value: 'http://www.w3.org/2001/XMLSchema#string' } }
370
+ };
371
+
372
+ // Output: <<( <http://example.org/s> <http://example.org/p> "value" )>>
373
+ ```
374
+
375
+ ### Reified Triples with Annotations
376
+
377
+ ```turtle
378
+ # Input
379
+ ex:subject ex:predicate ex:object {| ex:source ex:source1 |} .
380
+
381
+ # Serialized correctly with annotations
382
+ ```
383
+
384
+ ### Language Direction (RDF 1.2)
385
+
386
+ ```typescript
387
+ const literal = DataFactory.literal('مرحبا', 'ar--rtl');
388
+ // Output in Turtle: "مرحبا"@ar--rtl
389
+ // Output in JSON-LD: { "@value": "مرحبا", "@language": "ar", "@direction": "rtl" }
390
+ ```
391
+
392
+ ## API Reference
393
+
394
+ ### Interfaces
395
+
396
+ #### `ISerializer`
397
+
398
+ ```typescript
399
+ interface ISerializer {
400
+ serializeQuad(quad: Quad | Rdf12Quad, options?: SerializerOptions): string;
401
+ serialize(quads: Iterable<Quad | Rdf12Quad>, options?: SerializerOptions): string;
402
+ format(quads: Iterable<Quad | Rdf12Quad>, options?: SerializerOptions): SerializationResult;
403
+ }
404
+ ```
405
+
406
+ #### `SerializationResult`
407
+
408
+ ```typescript
409
+ interface SerializationResult {
410
+ output: string;
411
+ warnings?: string[];
412
+ sourceMap?: SourceMapEntry[];
413
+ }
414
+ ```
415
+
416
+ #### `ISparqlFormatter`
417
+
418
+ ```typescript
419
+ interface ISparqlFormatter {
420
+ formatFromText(query: string, options?: SerializerOptions): SerializationResult;
421
+ formatFromTokens(tokens: unknown[], options?: SerializerOptions): SerializationResult;
422
+ }
423
+ ```
424
+
425
+ ## VS Code Formatter
426
+
427
+ Here's how to create a document formatter for Turtle files in VS Code:
428
+
429
+ ```typescript
430
+ import * as vscode from 'vscode';
431
+ import { TurtleParser } from '@faubulous/mentor-rdf-parsers';
432
+ import { TurtleSerializer } from '@faubulous/mentor-rdf-serializers';
433
+
434
+ export class TurtleDocumentFormatter implements vscode.DocumentFormattingEditProvider {
435
+ private parser = new TurtleParser();
436
+ private serializer = new TurtleSerializer();
437
+
438
+ provideDocumentFormattingEdits(
439
+ document: vscode.TextDocument,
440
+ options: vscode.FormattingOptions,
441
+ token: vscode.CancellationToken
442
+ ): vscode.TextEdit[] {
443
+ const text = document.getText();
444
+
445
+ // Parse the document
446
+ const parseResult = this.parser.parse(text);
447
+
448
+ if (parseResult.errors.length > 0) {
449
+ // Don't format if there are parse errors
450
+ return [];
451
+ }
452
+
453
+ // Get user preferences from VS Code settings
454
+ const config = vscode.workspace.getConfiguration('turtle');
455
+
456
+ // Serialize with formatting options
457
+ const result = this.serializer.serialize(parseResult.quads, {
458
+ prefixes: parseResult.prefixes,
459
+ baseIri: parseResult.baseIri,
460
+ indent: options.insertSpaces ? ' '.repeat(options.tabSize) : '\t',
461
+ prettyPrint: true,
462
+ groupBySubject: true,
463
+ sort: config.get('sortStatements', true),
464
+ maxLineWidth: config.get('maxLineWidth', 80),
465
+ alignPredicates: config.get('alignPredicates', false),
466
+ blankNodeStyle: config.get('blankNodeStyle', 'auto'),
467
+ predicateListStyle: config.get('predicateListStyle', 'first-same-line'),
468
+ blankLinesBetweenSubjects: config.get('blankLinesBetweenSubjects', true)
469
+ });
470
+
471
+ // Return a single edit replacing the entire document
472
+ const fullRange = new vscode.Range(
473
+ document.positionAt(0),
474
+ document.positionAt(text.length)
475
+ );
476
+
477
+ return [vscode.TextEdit.replace(fullRange, result.output)];
478
+ }
479
+ }
480
+
481
+ // Register the formatter in your extension's activate function
482
+ export function activate(context: vscode.ExtensionContext) {
483
+ context.subscriptions.push(
484
+ vscode.languages.registerDocumentFormattingEditProvider(
485
+ { language: 'turtle', scheme: 'file' },
486
+ new TurtleDocumentFormatter()
487
+ )
488
+ );
489
+ }
490
+ ```
491
+
492
+ ### SPARQL Formatter for VS Code
493
+
494
+ ```typescript
495
+ import * as vscode from 'vscode';
496
+ import { SparqlFormatter } from '@faubulous/mentor-rdf-serializers';
497
+
498
+ export class SparqlDocumentFormatter implements vscode.DocumentFormattingEditProvider {
499
+ private formatter = new SparqlFormatter();
500
+
501
+ provideDocumentFormattingEdits(
502
+ document: vscode.TextDocument,
503
+ options: vscode.FormattingOptions,
504
+ token: vscode.CancellationToken
505
+ ): vscode.TextEdit[] {
506
+ const text = document.getText();
507
+ const config = vscode.workspace.getConfiguration('sparql');
508
+
509
+ const result = this.formatter.formatFromText(text, {
510
+ indent: options.insertSpaces ? ' '.repeat(options.tabSize) : '\t',
511
+ prettyPrint: true,
512
+ uppercaseKeywords: config.get('uppercaseKeywords', true),
513
+ alignPatterns: config.get('alignPatterns', true),
514
+ sameBraceLine: config.get('sameBraceLine', true),
515
+ separateClauses: config.get('separateClauses', true),
516
+ maxLineWidth: config.get('maxLineWidth', 80)
517
+ });
518
+
519
+ const fullRange = new vscode.Range(
520
+ document.positionAt(0),
521
+ document.positionAt(text.length)
522
+ );
523
+
524
+ return [vscode.TextEdit.replace(fullRange, result.output)];
525
+ }
526
+ }
527
+ ```
528
+
529
+ ### Range Formatting (Format Selection)
530
+
531
+ For formatting only a selected range, use the `TokenSerializer` to preserve surrounding content:
532
+
533
+ ```typescript
534
+ import { TurtleParser } from '@faubulous/mentor-rdf-parsers';
535
+ import { TokenSerializer } from '@faubulous/mentor-rdf-serializers';
536
+
537
+ export class TurtleRangeFormatter implements vscode.DocumentRangeFormattingEditProvider {
538
+ private parser = new TurtleParser();
539
+ private tokenSerializer = new TokenSerializer();
540
+
541
+ provideDocumentRangeFormattingEdits(
542
+ document: vscode.TextDocument,
543
+ range: vscode.Range,
544
+ options: vscode.FormattingOptions,
545
+ token: vscode.CancellationToken
546
+ ): vscode.TextEdit[] {
547
+ const text = document.getText();
548
+ const parseResult = this.parser.parse(text);
549
+
550
+ if (parseResult.errors.length > 0) {
551
+ return [];
552
+ }
553
+
554
+ // Get byte offsets for the selected range
555
+ const startOffset = document.offsetAt(range.start);
556
+ const endOffset = document.offsetAt(range.end);
557
+
558
+ // Serialize only tokens within the range
559
+ const result = this.tokenSerializer.serializeRange(
560
+ parseResult.tokens,
561
+ startOffset,
562
+ endOffset,
563
+ { preserveComments: true, preserveBlankNodeIds: true }
564
+ );
565
+
566
+ return [vscode.TextEdit.replace(range, result.output)];
567
+ }
568
+ }
569
+ ```
570
+
571
+ ## License
572
+
573
+ [LGPL-2.1-or-later](https://github.com/faubulous/mentor-rdf-parsers/blob/main/LICENSE)
574
+
575
+ ## Contributing
576
+
577
+ Contributions are welcome! Please feel free to submit a Pull Request.
578
+
579
+ ## Related Projects
580
+
581
+ - [@faubulous/mentor-rdf-parsers](https://github.com/faubulous/mentor-rdf-parsers) - RDF parsing library
582
+ - [@faubulous/mentor-vscode](https://github.com/faubulous/mentor-vscode) - RDF IDE and workbench
@@ -0,0 +1,63 @@
1
+ import type { BlankNode, Literal, NamedNode, Quad, Term, Variable } from '@rdfjs/types';
2
+ import type { ISerializer, Rdf12Quad, Rdf12Term, RdfSyntax, SerializationResult, SerializerOptions, TripleTerm } from './types.js';
3
+ /**
4
+ * Abstract base class for RDF serializers.
5
+ * Provides common functionality for serializing terms and literals.
6
+ */
7
+ export declare abstract class BaseSerializer implements ISerializer {
8
+ abstract readonly syntax: RdfSyntax;
9
+ /**
10
+ * Whether this serializer supports prefixed names.
11
+ */
12
+ protected supportsPrefixes: boolean;
13
+ /**
14
+ * Whether this serializer supports the 'a' shorthand for rdf:type.
15
+ */
16
+ protected supportsRdfTypeShorthand: boolean;
17
+ /**
18
+ * Whether this serializer supports RDF 1.2 features (triple terms, reifiers, annotations).
19
+ */
20
+ protected supportsRdf12: boolean;
21
+ /**
22
+ * Serializes a single quad to a string.
23
+ */
24
+ abstract serializeQuad(quad: Quad | Rdf12Quad, options?: SerializerOptions): string;
25
+ /**
26
+ * Serializes an array of quads to a string.
27
+ */
28
+ abstract serialize(quads: Iterable<Quad | Rdf12Quad>, options?: SerializerOptions): string;
29
+ /**
30
+ * Serializes quads with formatting, returning detailed result.
31
+ */
32
+ format(quads: Iterable<Quad | Rdf12Quad>, options?: SerializerOptions): SerializationResult;
33
+ /**
34
+ * Serializes a named node (IRI).
35
+ */
36
+ protected serializeNamedNode(node: NamedNode, options: Required<SerializerOptions>): string;
37
+ /**
38
+ * Serializes a blank node.
39
+ */
40
+ protected serializeBlankNode(node: BlankNode, _options: Required<SerializerOptions>): string;
41
+ /**
42
+ * Serializes a literal value.
43
+ */
44
+ protected serializeLiteral(literal: Literal, options: Required<SerializerOptions>): string;
45
+ /**
46
+ * Serializes a variable (SPARQL).
47
+ */
48
+ protected serializeVariable(variable: Variable, _options: Required<SerializerOptions>): string;
49
+ /**
50
+ * Serializes an RDF 1.2 Triple Term.
51
+ * Syntax: <<( subject predicate object )>>
52
+ */
53
+ protected serializeTripleTerm(tripleTerm: TripleTerm, options: Required<SerializerOptions>): string;
54
+ /**
55
+ * Serializes any RDF term.
56
+ */
57
+ protected serializeTerm(term: Term | Rdf12Term, options: Required<SerializerOptions>): string;
58
+ /**
59
+ * Gets merged options with defaults.
60
+ */
61
+ protected getOptions(options?: SerializerOptions): Required<SerializerOptions>;
62
+ }
63
+ //# sourceMappingURL=base-serializer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-serializer.d.ts","sourceRoot":"","sources":["../src/base-serializer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAgB,MAAM,cAAc,CAAC;AACtG,OAAO,KAAK,EACR,WAAW,EACX,SAAS,EACT,SAAS,EACT,SAAS,EACT,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACb,MAAM,YAAY,CAAC;AAqBpB;;;GAGG;AACH,8BAAsB,cAAe,YAAW,WAAW;IACvD,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAEpC;;OAEG;IACH,SAAS,CAAC,gBAAgB,EAAE,OAAO,CAAS;IAE5C;;OAEG;IACH,SAAS,CAAC,wBAAwB,EAAE,OAAO,CAAS;IAEpD;;OAEG;IACH,SAAS,CAAC,aAAa,EAAE,OAAO,CAAS;IAEzC;;OAEG;IACH,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM;IAEnF;;OAEG;IACH,QAAQ,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,GAAG,SAAS,CAAC,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM;IAE1F;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,GAAG,SAAS,CAAC,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,mBAAmB;IAM3F;;OAEG;IACH,SAAS,CAAC,kBAAkB,CACxB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GACrC,MAAM;IAmBT;;OAEG;IACH,SAAS,CAAC,kBAAkB,CACxB,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GACtC,MAAM;IAIT;;OAEG;IACH,SAAS,CAAC,gBAAgB,CACtB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GACrC,MAAM;IAoDT;;OAEG;IACH,SAAS,CAAC,iBAAiB,CACvB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GACtC,MAAM;IAIT;;;OAGG;IACH,SAAS,CAAC,mBAAmB,CACzB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GACrC,MAAM;IAYT;;OAEG;IACH,SAAS,CAAC,aAAa,CACnB,IAAI,EAAE,IAAI,GAAG,SAAS,EACtB,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GACrC,MAAM;IAmBT;;OAEG;IACH,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,CAAC;CAGjF"}