@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.
- package/README.md +582 -0
- package/dist/base-serializer.d.ts +63 -0
- package/dist/base-serializer.d.ts.map +1 -0
- package/dist/base-serializer.js +144 -0
- package/dist/base-serializer.js.map +1 -0
- package/dist/base-token-formatter.d.ts +225 -0
- package/dist/base-token-formatter.d.ts.map +1 -0
- package/dist/base-token-formatter.js +521 -0
- package/dist/base-token-formatter.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/jsonld/serializer.d.ts +99 -0
- package/dist/jsonld/serializer.d.ts.map +1 -0
- package/dist/jsonld/serializer.js +282 -0
- package/dist/jsonld/serializer.js.map +1 -0
- package/dist/n3/formatter.d.ts +105 -0
- package/dist/n3/formatter.d.ts.map +1 -0
- package/dist/n3/formatter.js +444 -0
- package/dist/n3/formatter.js.map +1 -0
- package/dist/n3/serializer.d.ts +103 -0
- package/dist/n3/serializer.d.ts.map +1 -0
- package/dist/n3/serializer.js +134 -0
- package/dist/n3/serializer.js.map +1 -0
- package/dist/nquads/formatter.d.ts +44 -0
- package/dist/nquads/formatter.d.ts.map +1 -0
- package/dist/nquads/formatter.js +116 -0
- package/dist/nquads/formatter.js.map +1 -0
- package/dist/nquads/serializer.d.ts +38 -0
- package/dist/nquads/serializer.d.ts.map +1 -0
- package/dist/nquads/serializer.js +70 -0
- package/dist/nquads/serializer.js.map +1 -0
- package/dist/ntriples/formatter.d.ts +44 -0
- package/dist/ntriples/formatter.d.ts.map +1 -0
- package/dist/ntriples/formatter.js +116 -0
- package/dist/ntriples/formatter.js.map +1 -0
- package/dist/ntriples/serializer.d.ts +38 -0
- package/dist/ntriples/serializer.d.ts.map +1 -0
- package/dist/ntriples/serializer.js +79 -0
- package/dist/ntriples/serializer.js.map +1 -0
- package/dist/sorting/index.d.ts +5 -0
- package/dist/sorting/index.d.ts.map +1 -0
- package/dist/sorting/index.js +5 -0
- package/dist/sorting/index.js.map +1 -0
- package/dist/sorting/strategies.d.ts +46 -0
- package/dist/sorting/strategies.d.ts.map +1 -0
- package/dist/sorting/strategies.js +259 -0
- package/dist/sorting/strategies.js.map +1 -0
- package/dist/sparql/formatter.d.ts +103 -0
- package/dist/sparql/formatter.d.ts.map +1 -0
- package/dist/sparql/formatter.js +764 -0
- package/dist/sparql/formatter.js.map +1 -0
- package/dist/token-serializer.d.ts +96 -0
- package/dist/token-serializer.d.ts.map +1 -0
- package/dist/token-serializer.js +456 -0
- package/dist/token-serializer.js.map +1 -0
- package/dist/trig/formatter.d.ts +99 -0
- package/dist/trig/formatter.d.ts.map +1 -0
- package/dist/trig/formatter.js +418 -0
- package/dist/trig/formatter.js.map +1 -0
- package/dist/trig/serializer.d.ts +39 -0
- package/dist/trig/serializer.d.ts.map +1 -0
- package/dist/trig/serializer.js +170 -0
- package/dist/trig/serializer.js.map +1 -0
- package/dist/turtle/formatter.d.ts +56 -0
- package/dist/turtle/formatter.d.ts.map +1 -0
- package/dist/turtle/formatter.js +325 -0
- package/dist/turtle/formatter.js.map +1 -0
- package/dist/turtle/serializer.d.ts +87 -0
- package/dist/turtle/serializer.d.ts.map +1 -0
- package/dist/turtle/serializer.js +343 -0
- package/dist/turtle/serializer.js.map +1 -0
- package/dist/types.d.ts +323 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +157 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +446 -0
- package/dist/utils.js.map +1 -0
- 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"}
|