@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
|
@@ -0,0 +1,764 @@
|
|
|
1
|
+
import { RdfToken, SparqlLexer } from '@faubulous/mentor-rdf-parsers';
|
|
2
|
+
import { BaseTokenFormatter, } from '../base-token-formatter.js';
|
|
3
|
+
/**
|
|
4
|
+
* Formatter for SPARQL queries and updates.
|
|
5
|
+
*
|
|
6
|
+
* Uses the W3C-compliant SparqlLexer from mentor-rdf-parsers for tokenization.
|
|
7
|
+
*
|
|
8
|
+
* This formatter can:
|
|
9
|
+
* - Format SPARQL 1.1/1.2 queries and updates
|
|
10
|
+
* - Normalize keyword casing
|
|
11
|
+
* - Apply consistent indentation
|
|
12
|
+
* - Align triple patterns
|
|
13
|
+
* - Preserve comments
|
|
14
|
+
* - Preserve source newlines and blank lines
|
|
15
|
+
*
|
|
16
|
+
* @see https://www.w3.org/TR/sparql12-query/
|
|
17
|
+
*/
|
|
18
|
+
export class SparqlFormatter extends BaseTokenFormatter {
|
|
19
|
+
lexer = new SparqlLexer();
|
|
20
|
+
// ========================================================================
|
|
21
|
+
// Public API
|
|
22
|
+
// ========================================================================
|
|
23
|
+
formatFromText(query, options) {
|
|
24
|
+
const opts = this.getOptions(options);
|
|
25
|
+
const result = this.lexer.tokenize(query);
|
|
26
|
+
if (result.errors.length > 0) {
|
|
27
|
+
return { output: query };
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
return this.formatTokenStream(result.tokens, opts);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
formatFromTokens(tokens, options) {
|
|
34
|
+
const opts = this.getOptions(options);
|
|
35
|
+
return this.formatTokenStream(tokens, opts);
|
|
36
|
+
}
|
|
37
|
+
// ========================================================================
|
|
38
|
+
// BaseTokenFormatter abstract implementations
|
|
39
|
+
// ========================================================================
|
|
40
|
+
getOptions(options) {
|
|
41
|
+
const base = this.mergeBaseOptions(options);
|
|
42
|
+
return {
|
|
43
|
+
...base,
|
|
44
|
+
uppercaseKeywords: options?.uppercaseKeywords ?? true,
|
|
45
|
+
lowercaseKeywords: options?.lowercaseKeywords ?? false,
|
|
46
|
+
alignPatterns: options?.alignPatterns ?? true,
|
|
47
|
+
sameBraceLine: options?.sameBraceLine ?? true,
|
|
48
|
+
separateClauses: options?.separateClauses ?? true,
|
|
49
|
+
spaceBeforePunctuation: options?.spaceBeforePunctuation ?? false,
|
|
50
|
+
maxLineWidth: options?.maxLineWidth ?? base.maxLineWidth,
|
|
51
|
+
alignPredicates: options?.alignPredicates ?? base.alignPredicates,
|
|
52
|
+
alignObjects: options?.alignObjects ?? base.alignObjects,
|
|
53
|
+
objectListStyle: options?.objectListStyle ?? base.objectListStyle,
|
|
54
|
+
predicateListStyle: options?.predicateListStyle ?? base.predicateListStyle,
|
|
55
|
+
blankLinesBetweenSubjects: options?.blankLinesBetweenSubjects ?? base.blankLinesBetweenSubjects,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
createContext(opts) {
|
|
59
|
+
return {
|
|
60
|
+
...this.createBaseContext(),
|
|
61
|
+
opts,
|
|
62
|
+
justEndedPrefix: false,
|
|
63
|
+
inWhereBlock: false,
|
|
64
|
+
functionCallDepth: 0,
|
|
65
|
+
hasFromClause: false,
|
|
66
|
+
isAskQuery: false,
|
|
67
|
+
lastWasInlineBlock: false,
|
|
68
|
+
lastCommentPartIndex: 0,
|
|
69
|
+
lastCommentHadBlankLine: false,
|
|
70
|
+
inValuesClause: false,
|
|
71
|
+
valuesDepth: 0,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
formatTokenValue(token, opts) {
|
|
75
|
+
if (this.isLowercaseOnly(token)) {
|
|
76
|
+
return token.image.toLowerCase();
|
|
77
|
+
}
|
|
78
|
+
if (this.isKeyword(token)) {
|
|
79
|
+
if (opts.lowercaseKeywords)
|
|
80
|
+
return token.image.toLowerCase();
|
|
81
|
+
if (opts.uppercaseKeywords)
|
|
82
|
+
return token.image.toUpperCase();
|
|
83
|
+
}
|
|
84
|
+
return token.image;
|
|
85
|
+
}
|
|
86
|
+
// ========================================================================
|
|
87
|
+
// Inline block calculation
|
|
88
|
+
// ========================================================================
|
|
89
|
+
/**
|
|
90
|
+
* Calculates the length of a block's content (from { to matching }).
|
|
91
|
+
* Returns -1 if the block should use multi-line formatting.
|
|
92
|
+
*/
|
|
93
|
+
calculateBlockLength(tokens, startIndex, opts) {
|
|
94
|
+
let depth = 0;
|
|
95
|
+
let length = 0;
|
|
96
|
+
let needsSpace = false;
|
|
97
|
+
let lastTokenType = null;
|
|
98
|
+
let lastNonWsToken = null;
|
|
99
|
+
for (let i = startIndex; i < tokens.length; i++) {
|
|
100
|
+
const token = tokens[i];
|
|
101
|
+
if (token.tokenType === RdfToken.WS)
|
|
102
|
+
continue;
|
|
103
|
+
// Source has explicit newlines - preserve multi-line format
|
|
104
|
+
if (lastNonWsToken && token.startLine !== undefined && lastNonWsToken.endLine !== undefined) {
|
|
105
|
+
if (token.startLine > lastNonWsToken.endLine)
|
|
106
|
+
return -1;
|
|
107
|
+
}
|
|
108
|
+
if (token.tokenType === RdfToken.LCURLY) {
|
|
109
|
+
if (depth > 0) {
|
|
110
|
+
const nestedLength = this.calculateBlockLength(tokens, i + 1, opts);
|
|
111
|
+
if (nestedLength < 0)
|
|
112
|
+
return -1;
|
|
113
|
+
length += (needsSpace ? 1 : 0) + 1 + nestedLength + 1;
|
|
114
|
+
needsSpace = true;
|
|
115
|
+
let nestedDepth = 1;
|
|
116
|
+
i++;
|
|
117
|
+
while (i < tokens.length && nestedDepth > 0) {
|
|
118
|
+
if (tokens[i].tokenType === RdfToken.LCURLY)
|
|
119
|
+
nestedDepth++;
|
|
120
|
+
else if (tokens[i].tokenType === RdfToken.RCURLY)
|
|
121
|
+
nestedDepth--;
|
|
122
|
+
i++;
|
|
123
|
+
}
|
|
124
|
+
i--;
|
|
125
|
+
lastTokenType = RdfToken.RCURLY;
|
|
126
|
+
lastNonWsToken = tokens[i];
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
depth++;
|
|
130
|
+
length += (needsSpace ? 1 : 0) + 1;
|
|
131
|
+
needsSpace = false;
|
|
132
|
+
lastTokenType = token.tokenType;
|
|
133
|
+
lastNonWsToken = token;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (token.tokenType === RdfToken.RCURLY) {
|
|
137
|
+
depth--;
|
|
138
|
+
if (depth < 0) {
|
|
139
|
+
length += (needsSpace ? 1 : 0) + 1;
|
|
140
|
+
return length;
|
|
141
|
+
}
|
|
142
|
+
length += (needsSpace ? 1 : 0) + 1;
|
|
143
|
+
needsSpace = true;
|
|
144
|
+
lastTokenType = token.tokenType;
|
|
145
|
+
lastNonWsToken = token;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (token.tokenType === RdfToken.PERIOD || token.tokenType === RdfToken.SEMICOLON) {
|
|
149
|
+
length += token.image.length;
|
|
150
|
+
needsSpace = true;
|
|
151
|
+
lastTokenType = token.tokenType;
|
|
152
|
+
lastNonWsToken = token;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (token.tokenType === RdfToken.LPARENT || token.tokenType === RdfToken.LBRACKET) {
|
|
156
|
+
const lastWasFunction = lastTokenType && this.isFunctionKeyword({ tokenType: lastTokenType });
|
|
157
|
+
length += (needsSpace && !lastWasFunction ? 1 : 0) + token.image.length;
|
|
158
|
+
needsSpace = false;
|
|
159
|
+
lastTokenType = token.tokenType;
|
|
160
|
+
lastNonWsToken = token;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (token.tokenType === RdfToken.RPARENT || token.tokenType === RdfToken.RBRACKET) {
|
|
164
|
+
length += token.image.length;
|
|
165
|
+
needsSpace = true;
|
|
166
|
+
lastTokenType = token.tokenType;
|
|
167
|
+
lastNonWsToken = token;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (token.tokenType === RdfToken.COMMA) {
|
|
171
|
+
length += token.image.length;
|
|
172
|
+
needsSpace = true;
|
|
173
|
+
lastTokenType = token.tokenType;
|
|
174
|
+
lastNonWsToken = token;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const tokenLength = this.formatTokenValue(token, opts).length;
|
|
178
|
+
const isOpenParen = lastTokenType === RdfToken.LPARENT || lastTokenType === RdfToken.LBRACKET;
|
|
179
|
+
length += (needsSpace && !isOpenParen ? 1 : 0) + tokenLength;
|
|
180
|
+
needsSpace = true;
|
|
181
|
+
lastTokenType = token.tokenType;
|
|
182
|
+
lastNonWsToken = token;
|
|
183
|
+
}
|
|
184
|
+
return -1;
|
|
185
|
+
}
|
|
186
|
+
shouldBlockBeInline(ctx, tokens, startIndex) {
|
|
187
|
+
if (ctx.opts.maxLineWidth <= 0)
|
|
188
|
+
return false;
|
|
189
|
+
const blockLength = this.calculateBlockLength(tokens, startIndex, ctx.opts);
|
|
190
|
+
if (blockLength < 0)
|
|
191
|
+
return false;
|
|
192
|
+
return ctx.currentLineLength + blockLength <= ctx.opts.maxLineWidth;
|
|
193
|
+
}
|
|
194
|
+
// ========================================================================
|
|
195
|
+
// SPARQL-specific token handlers
|
|
196
|
+
// ========================================================================
|
|
197
|
+
handleOpenBrace(ctx, tokens, startIndex) {
|
|
198
|
+
const shouldBeInline = this.shouldBlockBeInline(ctx, tokens, startIndex);
|
|
199
|
+
const le = ctx.opts.lineEnd;
|
|
200
|
+
const ind = ctx.opts.indent;
|
|
201
|
+
// When a blank line or newline was detected in the source *before* the
|
|
202
|
+
// opening brace, we need to honour it here so that the blank line
|
|
203
|
+
// appears before the brace, not after it. This mirrors the behaviour
|
|
204
|
+
// in handleSparqlTokenSpacing but is specialised for structural
|
|
205
|
+
// curly-brace tokens which bypass that helper.
|
|
206
|
+
if (ctx.needsNewline) {
|
|
207
|
+
if (!ctx.lastWasNewline)
|
|
208
|
+
this.addPart(ctx, le, le, true);
|
|
209
|
+
if (ctx.needsBlankLine) {
|
|
210
|
+
this.addPart(ctx, le, le, true);
|
|
211
|
+
ctx.needsBlankLine = false;
|
|
212
|
+
}
|
|
213
|
+
this.addPart(ctx, this.getIndent(ctx.indentLevel, ind), le);
|
|
214
|
+
ctx.lastWasNewline = false;
|
|
215
|
+
ctx.needsNewline = false;
|
|
216
|
+
}
|
|
217
|
+
else if (ctx.needsSpace && ctx.parts.length > 0 && ctx.opts.sameBraceLine) {
|
|
218
|
+
this.addPart(ctx, ' ', le);
|
|
219
|
+
}
|
|
220
|
+
else if (!ctx.opts.sameBraceLine) {
|
|
221
|
+
this.addPart(ctx, le + this.getIndent(ctx.indentLevel, ind), le, true);
|
|
222
|
+
}
|
|
223
|
+
this.addPart(ctx, '{', le);
|
|
224
|
+
ctx.lastWasNewline = false;
|
|
225
|
+
if (shouldBeInline) {
|
|
226
|
+
this.pushScope(ctx, 'curly', true, false);
|
|
227
|
+
ctx.needsNewline = false;
|
|
228
|
+
ctx.needsSpace = true;
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
this.pushScope(ctx, 'curly', false, false);
|
|
232
|
+
ctx.needsNewline = ctx.opts.prettyPrint;
|
|
233
|
+
ctx.needsSpace = false;
|
|
234
|
+
}
|
|
235
|
+
ctx.inPrefix = false;
|
|
236
|
+
ctx.triplePosition = 0;
|
|
237
|
+
ctx.lastSubject = null;
|
|
238
|
+
// Track the VALUES block depth so we can clear inValuesClause
|
|
239
|
+
// when the matching close brace is encountered.
|
|
240
|
+
if (ctx.inValuesClause && ctx.valuesDepth === 0) {
|
|
241
|
+
ctx.valuesDepth = ctx.indentLevel;
|
|
242
|
+
}
|
|
243
|
+
// The source-originated newline/blank-line information has now been
|
|
244
|
+
// consumed for this brace, so it should not affect the next token.
|
|
245
|
+
ctx.sourceNewline = false;
|
|
246
|
+
}
|
|
247
|
+
handleCloseBrace(ctx) {
|
|
248
|
+
const scope = this.currentScope(ctx);
|
|
249
|
+
const isInline = scope?.isInline ?? false;
|
|
250
|
+
const le = ctx.opts.lineEnd;
|
|
251
|
+
const ind = ctx.opts.indent;
|
|
252
|
+
this.popScope(ctx);
|
|
253
|
+
if (isInline) {
|
|
254
|
+
this.addPart(ctx, ' }', le);
|
|
255
|
+
}
|
|
256
|
+
else if (ctx.opts.prettyPrint) {
|
|
257
|
+
this.addPart(ctx, le + this.getIndent(ctx.indentLevel, ind), le, true);
|
|
258
|
+
this.addPart(ctx, '}', le);
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
this.addPart(ctx, '}', le);
|
|
262
|
+
}
|
|
263
|
+
ctx.lastWasNewline = false;
|
|
264
|
+
ctx.needsNewline = ctx.opts.prettyPrint && !isInline;
|
|
265
|
+
ctx.needsSpace = isInline;
|
|
266
|
+
// Only clear inWhereBlock when exiting the outermost WHERE block
|
|
267
|
+
// (i.e. indent level returns to 0). Inner blocks like VALUES { }
|
|
268
|
+
// or FILTER NOT EXISTS { } should not clear this flag.
|
|
269
|
+
if (ctx.indentLevel === 0) {
|
|
270
|
+
ctx.inWhereBlock = false;
|
|
271
|
+
}
|
|
272
|
+
ctx.triplePosition = 0;
|
|
273
|
+
ctx.inlineStatement = false;
|
|
274
|
+
ctx.lastSubject = null;
|
|
275
|
+
ctx.lastWasInlineBlock = isInline;
|
|
276
|
+
// Clear VALUES clause tracking when matching brace closes.
|
|
277
|
+
if (ctx.inValuesClause && ctx.indentLevel < ctx.valuesDepth) {
|
|
278
|
+
ctx.inValuesClause = false;
|
|
279
|
+
ctx.valuesDepth = 0;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
handleSparqlPeriod(ctx, nextToken) {
|
|
283
|
+
const le = ctx.opts.lineEnd;
|
|
284
|
+
if (ctx.opts.spaceBeforePunctuation && !ctx.inPrefix && ctx.parts.length > 0) {
|
|
285
|
+
this.addPart(ctx, ' ', le);
|
|
286
|
+
}
|
|
287
|
+
this.addPart(ctx, '.', le);
|
|
288
|
+
if (ctx.inPrefix) {
|
|
289
|
+
ctx.needsNewline = ctx.opts.prettyPrint;
|
|
290
|
+
const nextIsPrefix = nextToken && (nextToken.tokenType === RdfToken.PREFIX || nextToken.tokenType === RdfToken.BASE);
|
|
291
|
+
if (!nextIsPrefix && nextToken) {
|
|
292
|
+
ctx.needsNewline = ctx.opts.prettyPrint;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
else if (ctx.indentLevel > 0) {
|
|
296
|
+
ctx.needsNewline = ctx.opts.prettyPrint;
|
|
297
|
+
}
|
|
298
|
+
ctx.needsSpace = true;
|
|
299
|
+
ctx.inPrefix = false;
|
|
300
|
+
ctx.triplePosition = 0;
|
|
301
|
+
ctx.inlineStatement = false;
|
|
302
|
+
}
|
|
303
|
+
handleSparqlSemicolon(ctx) {
|
|
304
|
+
const le = ctx.opts.lineEnd;
|
|
305
|
+
const ind = ctx.opts.indent;
|
|
306
|
+
if (ctx.opts.spaceBeforePunctuation && ctx.parts.length > 0) {
|
|
307
|
+
this.addPart(ctx, ' ', le);
|
|
308
|
+
}
|
|
309
|
+
this.addPart(ctx, ';', le);
|
|
310
|
+
// Inline statement takes priority: source had it on one line and it fits.
|
|
311
|
+
if (ctx.inlineStatement) {
|
|
312
|
+
ctx.needsNewline = false;
|
|
313
|
+
ctx.needsSpace = true;
|
|
314
|
+
ctx.triplePosition = 1;
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const shouldMultiLine = ctx.opts.predicateListStyle === 'multi-line' ||
|
|
318
|
+
(ctx.opts.predicateListStyle === 'first-same-line' && ctx.indentLevel > 0);
|
|
319
|
+
if (ctx.opts.predicateListStyle === 'single-line') {
|
|
320
|
+
ctx.needsNewline = false;
|
|
321
|
+
ctx.needsSpace = true;
|
|
322
|
+
}
|
|
323
|
+
else if (shouldMultiLine && ctx.opts.prettyPrint) {
|
|
324
|
+
const extra = this.inBracketScope(ctx) ? '' : ind;
|
|
325
|
+
this.addPart(ctx, le + this.getIndent(ctx.indentLevel, ind) + extra, le, true);
|
|
326
|
+
ctx.lastWasNewline = true;
|
|
327
|
+
ctx.needsNewline = false;
|
|
328
|
+
ctx.needsSpace = false;
|
|
329
|
+
}
|
|
330
|
+
else if (ctx.opts.prettyPrint) {
|
|
331
|
+
const extra = this.inBracketScope(ctx) ? '' : ind;
|
|
332
|
+
this.addPart(ctx, le + this.getIndent(ctx.indentLevel, ind) + extra, le, true);
|
|
333
|
+
ctx.lastWasNewline = true;
|
|
334
|
+
ctx.needsNewline = false;
|
|
335
|
+
ctx.needsSpace = false;
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
ctx.needsNewline = false;
|
|
339
|
+
ctx.needsSpace = true;
|
|
340
|
+
}
|
|
341
|
+
ctx.triplePosition = 1;
|
|
342
|
+
}
|
|
343
|
+
handleSparqlComma(ctx, nextToken) {
|
|
344
|
+
const le = ctx.opts.lineEnd;
|
|
345
|
+
this.addPart(ctx, ',', le);
|
|
346
|
+
if (ctx.opts.objectListStyle === 'multi-line') {
|
|
347
|
+
ctx.needsNewline = ctx.opts.prettyPrint && ctx.indentLevel > 0;
|
|
348
|
+
ctx.needsSpace = !ctx.needsNewline;
|
|
349
|
+
}
|
|
350
|
+
else if (ctx.opts.objectListStyle === 'auto' && ctx.opts.maxLineWidth > 0) {
|
|
351
|
+
const nextObjLen = nextToken ? nextToken.image.length + 1 : 0;
|
|
352
|
+
if (this.shouldWrap(ctx, nextObjLen, ctx.opts.maxLineWidth)) {
|
|
353
|
+
ctx.needsNewline = ctx.opts.prettyPrint;
|
|
354
|
+
ctx.needsSpace = !ctx.needsNewline;
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
ctx.needsSpace = true;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
ctx.needsSpace = true;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
handleSparqlOpenParen(ctx, token, tokens, index) {
|
|
365
|
+
const isLParen = token.tokenType === RdfToken.LPARENT;
|
|
366
|
+
const isLBracket = token.tokenType === RdfToken.LBRACKET;
|
|
367
|
+
const le = ctx.opts.lineEnd;
|
|
368
|
+
const ind = ctx.opts.indent;
|
|
369
|
+
if (isLParen) {
|
|
370
|
+
const lastWasFunction = ctx.lastNonWsToken && this.isFunctionKeyword(ctx.lastNonWsToken);
|
|
371
|
+
if (lastWasFunction)
|
|
372
|
+
ctx.functionCallDepth++;
|
|
373
|
+
}
|
|
374
|
+
const lastWasFunction = ctx.lastNonWsToken && this.isFunctionKeyword(ctx.lastNonWsToken);
|
|
375
|
+
if (ctx.needsNewline && ctx.functionCallDepth === 0 && !lastWasFunction) {
|
|
376
|
+
this.addPart(ctx, le + this.getIndent(ctx.indentLevel, ind), le, true);
|
|
377
|
+
ctx.lastWasNewline = true;
|
|
378
|
+
ctx.needsNewline = false;
|
|
379
|
+
}
|
|
380
|
+
else if (ctx.needsSpace && ctx.parts.length > 0) {
|
|
381
|
+
if (!isLParen || !lastWasFunction) {
|
|
382
|
+
this.addPart(ctx, ' ', le);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
ctx.needsNewline = false;
|
|
386
|
+
this.addPart(ctx, token.image, le);
|
|
387
|
+
ctx.needsSpace = false;
|
|
388
|
+
// Square bracket [ ] → push bracket scope (for blank node property lists)
|
|
389
|
+
if (isLBracket) {
|
|
390
|
+
this.pushScope(ctx, 'bracket', false, false);
|
|
391
|
+
}
|
|
392
|
+
// Multi-line parenthesis → push paren scope for proper indent
|
|
393
|
+
if (isLParen && this.isParenBlockMultiLine(tokens, index)) {
|
|
394
|
+
this.pushScope(ctx, 'paren', false, true);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
handleSparqlCloseParen(ctx, token) {
|
|
398
|
+
const le = ctx.opts.lineEnd;
|
|
399
|
+
const ind = ctx.opts.indent;
|
|
400
|
+
if (token.tokenType === RdfToken.RPARENT && ctx.functionCallDepth > 0) {
|
|
401
|
+
ctx.functionCallDepth--;
|
|
402
|
+
}
|
|
403
|
+
// Closing bracket ] for blank-node property lists
|
|
404
|
+
if (token.tokenType === RdfToken.RBRACKET) {
|
|
405
|
+
const scope = this.currentScope(ctx);
|
|
406
|
+
if (scope?.type === 'bracket') {
|
|
407
|
+
// Pop any trailing newline+indent from a semicolon
|
|
408
|
+
if (ctx.lastWasNewline && ctx.parts.length > 0) {
|
|
409
|
+
const lastPart = ctx.parts[ctx.parts.length - 1];
|
|
410
|
+
if (lastPart.includes(le) || /^\s+$/.test(lastPart)) {
|
|
411
|
+
ctx.parts.pop();
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
this.popScope(ctx);
|
|
415
|
+
if (ctx.opts.prettyPrint) {
|
|
416
|
+
this.addPart(ctx, le + this.getIndent(ctx.indentLevel, ind), le, true);
|
|
417
|
+
}
|
|
418
|
+
this.addPart(ctx, token.image, le);
|
|
419
|
+
ctx.lastWasNewline = false;
|
|
420
|
+
ctx.needsSpace = true;
|
|
421
|
+
ctx.needsNewline = false;
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
// Closing multi-line paren
|
|
426
|
+
if (token.tokenType === RdfToken.RPARENT) {
|
|
427
|
+
const scope = this.currentScope(ctx);
|
|
428
|
+
if (scope?.type === 'paren' && scope.isMultiLine) {
|
|
429
|
+
this.popScope(ctx);
|
|
430
|
+
if (ctx.opts.prettyPrint) {
|
|
431
|
+
this.addPart(ctx, le + this.getIndent(ctx.indentLevel, ind), le, true);
|
|
432
|
+
}
|
|
433
|
+
this.addPart(ctx, token.image, le);
|
|
434
|
+
ctx.lastWasNewline = false;
|
|
435
|
+
ctx.needsSpace = true;
|
|
436
|
+
ctx.needsNewline = false;
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
this.addPart(ctx, token.image, le);
|
|
441
|
+
ctx.needsSpace = true;
|
|
442
|
+
ctx.needsNewline = false;
|
|
443
|
+
}
|
|
444
|
+
// ========================================================================
|
|
445
|
+
// Comment handling
|
|
446
|
+
// ========================================================================
|
|
447
|
+
handleGroupComment(ctx, comment) {
|
|
448
|
+
const le = ctx.opts.lineEnd;
|
|
449
|
+
const ind = ctx.opts.indent;
|
|
450
|
+
if (ctx.parts.length > 0) {
|
|
451
|
+
if (ctx.lastNonWsToken && comment.startLine !== undefined &&
|
|
452
|
+
ctx.lastNonWsToken.endLine !== undefined &&
|
|
453
|
+
comment.startLine > ctx.lastNonWsToken.endLine) {
|
|
454
|
+
const lineGap = comment.startLine - ctx.lastNonWsToken.endLine;
|
|
455
|
+
if (lineGap > 1) {
|
|
456
|
+
if (!ctx.lastWasNewline)
|
|
457
|
+
this.addPart(ctx, le, le, true);
|
|
458
|
+
this.addPart(ctx, le, le, true);
|
|
459
|
+
this.addPart(ctx, this.getIndent(ctx.indentLevel, ind), le);
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
this.addPart(ctx, le + this.getIndent(ctx.indentLevel, ind), le, true);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
this.addPart(ctx, ' ', le);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
this.addPart(ctx, comment.image, le);
|
|
470
|
+
ctx.lastWasNewline = false;
|
|
471
|
+
ctx.needsNewline = true;
|
|
472
|
+
ctx.needsSpace = false;
|
|
473
|
+
ctx.lastWasComment = true;
|
|
474
|
+
ctx.lastNonWsToken = comment;
|
|
475
|
+
}
|
|
476
|
+
handleInlineComment(ctx, token) {
|
|
477
|
+
const le = ctx.opts.lineEnd;
|
|
478
|
+
const ind = ctx.opts.indent;
|
|
479
|
+
// Track where the first comment in a consecutive series starts in parts[],
|
|
480
|
+
// so that blank-line-between-subjects can be retroactively placed before the comment.
|
|
481
|
+
if (!ctx.lastWasComment) {
|
|
482
|
+
ctx.lastCommentPartIndex = ctx.parts.length;
|
|
483
|
+
ctx.lastCommentHadBlankLine = false;
|
|
484
|
+
}
|
|
485
|
+
if (ctx.needsNewline) {
|
|
486
|
+
if (!ctx.lastWasNewline)
|
|
487
|
+
this.addPart(ctx, le, le, true);
|
|
488
|
+
if (ctx.needsBlankLine) {
|
|
489
|
+
this.addPart(ctx, le, le, true);
|
|
490
|
+
ctx.needsBlankLine = false;
|
|
491
|
+
ctx.lastCommentHadBlankLine = true;
|
|
492
|
+
}
|
|
493
|
+
this.addPart(ctx, this.getIndent(ctx.indentLevel, ind), le);
|
|
494
|
+
ctx.lastWasNewline = false;
|
|
495
|
+
ctx.needsNewline = false;
|
|
496
|
+
}
|
|
497
|
+
else if (ctx.needsSpace && ctx.parts.length > 0) {
|
|
498
|
+
this.addPart(ctx, ' ', le);
|
|
499
|
+
}
|
|
500
|
+
this.addPart(ctx, token.image, le);
|
|
501
|
+
ctx.lastWasNewline = false;
|
|
502
|
+
ctx.needsNewline = true;
|
|
503
|
+
ctx.needsSpace = false;
|
|
504
|
+
ctx.lastWasComment = true;
|
|
505
|
+
}
|
|
506
|
+
// ========================================================================
|
|
507
|
+
// State tracking
|
|
508
|
+
// ========================================================================
|
|
509
|
+
updateClauseState(ctx, token) {
|
|
510
|
+
if (token.tokenType === RdfToken.PREFIX || token.tokenType === RdfToken.BASE)
|
|
511
|
+
ctx.inPrefix = true;
|
|
512
|
+
if (token.tokenType === RdfToken.WHERE)
|
|
513
|
+
ctx.inWhereBlock = true;
|
|
514
|
+
if (token.tokenType === RdfToken.ASK)
|
|
515
|
+
ctx.isAskQuery = true;
|
|
516
|
+
if (token.tokenType === RdfToken.FROM)
|
|
517
|
+
ctx.hasFromClause = true;
|
|
518
|
+
if (token.tokenType === RdfToken.VALUES)
|
|
519
|
+
ctx.inValuesClause = true;
|
|
520
|
+
}
|
|
521
|
+
handleClauseSeparation(ctx, token) {
|
|
522
|
+
const justOpenedBrace = ctx.lastNonWsToken?.tokenType === RdfToken.LCURLY;
|
|
523
|
+
const justClosedBrace = ctx.lastNonWsToken?.tokenType === RdfToken.RCURLY;
|
|
524
|
+
const isTopLevel = ctx.indentLevel === 0;
|
|
525
|
+
if (ctx.opts.separateClauses &&
|
|
526
|
+
this.isMajorClauseKeyword(token) &&
|
|
527
|
+
ctx.parts.length > 0 &&
|
|
528
|
+
!ctx.inPrefix &&
|
|
529
|
+
!ctx.justEndedPrefix &&
|
|
530
|
+
!ctx.lastWasComment &&
|
|
531
|
+
!ctx.lastWasInlineBlock &&
|
|
532
|
+
!justOpenedBrace &&
|
|
533
|
+
!justClosedBrace &&
|
|
534
|
+
!isTopLevel) {
|
|
535
|
+
ctx.needsBlankLine = true;
|
|
536
|
+
ctx.needsNewline = true;
|
|
537
|
+
}
|
|
538
|
+
if (ctx.opts.separateClauses &&
|
|
539
|
+
this.isNewlineKeyword(token) &&
|
|
540
|
+
ctx.parts.length > 0 &&
|
|
541
|
+
!ctx.inPrefix) {
|
|
542
|
+
if (token.tokenType === RdfToken.WHERE && ctx.isAskQuery && !ctx.hasFromClause) {
|
|
543
|
+
ctx.needsNewline = false;
|
|
544
|
+
ctx.needsSpace = true;
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
ctx.needsNewline = true;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
if (token.tokenType !== RdfToken.PREFIX && token.tokenType !== RdfToken.BASE) {
|
|
551
|
+
ctx.justEndedPrefix = false;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
handleTriplePosition(ctx, token, tokens, index, prevWasComment = false) {
|
|
555
|
+
if (!ctx.inWhereBlock || ctx.indentLevel <= 0 || ctx.functionCallDepth > 0 || ctx.inValuesClause) {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
if (this.isTermToken(token)) {
|
|
559
|
+
if (ctx.triplePosition === 0) {
|
|
560
|
+
if (ctx.opts.blankLinesBetweenSubjects && ctx.lastSubject !== null && token.image !== ctx.lastSubject) {
|
|
561
|
+
if (!ctx.needsBlankLine) {
|
|
562
|
+
if (prevWasComment && !ctx.lastCommentHadBlankLine) {
|
|
563
|
+
// A comment precedes this new subject. Insert the blank line
|
|
564
|
+
// *before* the comment block so the comment stays attached to
|
|
565
|
+
// its associated statement, not floating after a blank line.
|
|
566
|
+
ctx.parts.splice(ctx.lastCommentPartIndex, 0, ctx.opts.lineEnd);
|
|
567
|
+
}
|
|
568
|
+
else if (!prevWasComment) {
|
|
569
|
+
ctx.needsBlankLine = true;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
ctx.needsNewline = true;
|
|
573
|
+
}
|
|
574
|
+
ctx.lastSubject = token.image;
|
|
575
|
+
this.detectInlineStatement(ctx, tokens, index, ctx.opts.indent, ctx.opts.maxLineWidth);
|
|
576
|
+
}
|
|
577
|
+
ctx.triplePosition++;
|
|
578
|
+
if (ctx.triplePosition > 2)
|
|
579
|
+
ctx.triplePosition = 2;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
// ========================================================================
|
|
583
|
+
// Spacing & wrapping
|
|
584
|
+
// ========================================================================
|
|
585
|
+
handleLineWrapping(ctx, value) {
|
|
586
|
+
const le = ctx.opts.lineEnd;
|
|
587
|
+
const ind = ctx.opts.indent;
|
|
588
|
+
if (ctx.opts.maxLineWidth > 0 && !ctx.needsNewline && ctx.needsSpace) {
|
|
589
|
+
const spaceNeeded = ctx.parts.length > 0 && ctx.lastNonWsToken &&
|
|
590
|
+
!this.isOpeningBracket(ctx.lastNonWsToken) ? 1 : 0;
|
|
591
|
+
if (this.shouldWrap(ctx, spaceNeeded + value.length, ctx.opts.maxLineWidth)) {
|
|
592
|
+
this.addPart(ctx, le + this.getIndent(ctx.indentLevel, ind), le, true);
|
|
593
|
+
ctx.lastWasNewline = true;
|
|
594
|
+
ctx.needsNewline = false;
|
|
595
|
+
ctx.needsSpace = false;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
handleSparqlTokenSpacing(ctx, token) {
|
|
600
|
+
const le = ctx.opts.lineEnd;
|
|
601
|
+
const ind = ctx.opts.indent;
|
|
602
|
+
const isDatatypeContext = token.tokenType === RdfToken.DCARET ||
|
|
603
|
+
ctx.lastNonWsToken?.tokenType === RdfToken.DCARET;
|
|
604
|
+
const inFunctionCall = ctx.functionCallDepth > 0;
|
|
605
|
+
// Only suppress newlines in function calls when they are NOT from source.
|
|
606
|
+
// Source newlines (detected from token positions) should always be preserved.
|
|
607
|
+
const shouldAvoidNewline = isDatatypeContext || (inFunctionCall && !ctx.sourceNewline);
|
|
608
|
+
if (ctx.needsNewline && !shouldAvoidNewline) {
|
|
609
|
+
if (!ctx.lastWasNewline) {
|
|
610
|
+
this.addPart(ctx, le, le, true);
|
|
611
|
+
}
|
|
612
|
+
if (ctx.needsBlankLine) {
|
|
613
|
+
this.addPart(ctx, le, le, true);
|
|
614
|
+
ctx.needsBlankLine = false;
|
|
615
|
+
}
|
|
616
|
+
this.addPart(ctx, this.getIndent(ctx.indentLevel, ind), le);
|
|
617
|
+
ctx.lastWasNewline = false;
|
|
618
|
+
ctx.needsNewline = false;
|
|
619
|
+
}
|
|
620
|
+
else if (ctx.needsSpace && ctx.parts.length > 0) {
|
|
621
|
+
if (ctx.lastNonWsToken && !this.isOpeningBracket(ctx.lastNonWsToken)) {
|
|
622
|
+
const isOpenParen = token.tokenType === RdfToken.LPARENT;
|
|
623
|
+
const lastWasFunction = ctx.lastNonWsToken && this.isFunctionKeyword(ctx.lastNonWsToken);
|
|
624
|
+
if (!(isOpenParen && lastWasFunction) && !isDatatypeContext) {
|
|
625
|
+
this.addPart(ctx, ' ', le);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
ctx.lastWasNewline = false;
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
ctx.lastWasNewline = false;
|
|
632
|
+
}
|
|
633
|
+
if (shouldAvoidNewline) {
|
|
634
|
+
ctx.needsNewline = false;
|
|
635
|
+
ctx.needsBlankLine = false;
|
|
636
|
+
}
|
|
637
|
+
ctx.sourceNewline = false;
|
|
638
|
+
}
|
|
639
|
+
detectBlankLines(ctx, token) {
|
|
640
|
+
if (ctx.lastNonWsToken && token.startLine !== undefined && ctx.lastNonWsToken.endLine !== undefined) {
|
|
641
|
+
const lineGap = token.startLine - ctx.lastNonWsToken.endLine;
|
|
642
|
+
if (lineGap > 1) {
|
|
643
|
+
ctx.needsBlankLine = true;
|
|
644
|
+
ctx.needsNewline = true;
|
|
645
|
+
ctx.sourceNewline = true;
|
|
646
|
+
}
|
|
647
|
+
else if (lineGap === 1 && !ctx.lastWasNewline) {
|
|
648
|
+
ctx.needsNewline = true;
|
|
649
|
+
ctx.sourceNewline = true;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
handleSparqlPrefixIri(ctx, value) {
|
|
654
|
+
const le = ctx.opts.lineEnd;
|
|
655
|
+
const ind = ctx.opts.indent;
|
|
656
|
+
if (ctx.needsNewline) {
|
|
657
|
+
this.addPart(ctx, le + this.getIndent(ctx.indentLevel, ind), le, true);
|
|
658
|
+
ctx.lastWasNewline = true;
|
|
659
|
+
ctx.needsNewline = false;
|
|
660
|
+
}
|
|
661
|
+
else if (ctx.needsSpace && ctx.parts.length > 0) {
|
|
662
|
+
if (ctx.lastNonWsToken && !this.isOpeningBracket(ctx.lastNonWsToken)) {
|
|
663
|
+
this.addPart(ctx, ' ', le);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
this.addPart(ctx, value, le);
|
|
667
|
+
ctx.needsSpace = false;
|
|
668
|
+
ctx.needsNewline = ctx.opts.prettyPrint;
|
|
669
|
+
ctx.inPrefix = false;
|
|
670
|
+
ctx.justEndedPrefix = true;
|
|
671
|
+
}
|
|
672
|
+
formatTokenStream(tokens, options) {
|
|
673
|
+
const ctx = this.createContext(options);
|
|
674
|
+
const le = options.lineEnd;
|
|
675
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
676
|
+
const token = tokens[i];
|
|
677
|
+
const nextToken = tokens[i + 1];
|
|
678
|
+
// Skip whitespace
|
|
679
|
+
if (token.tokenType === RdfToken.WS) {
|
|
680
|
+
ctx.lastToken = token;
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
// Detect source blank lines
|
|
684
|
+
this.detectBlankLines(ctx, token);
|
|
685
|
+
// Handle inline comments
|
|
686
|
+
if (token.tokenType === RdfToken.COMMENT) {
|
|
687
|
+
this.handleInlineComment(ctx, token);
|
|
688
|
+
ctx.lastToken = token;
|
|
689
|
+
ctx.lastNonWsToken = token;
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
const value = this.formatTokenValue(token, options);
|
|
693
|
+
// State tracking
|
|
694
|
+
this.updateClauseState(ctx, token);
|
|
695
|
+
this.handleClauseSeparation(ctx, token);
|
|
696
|
+
const prevWasComment = ctx.lastWasComment;
|
|
697
|
+
ctx.lastWasComment = false;
|
|
698
|
+
ctx.lastWasInlineBlock = false;
|
|
699
|
+
// ── Structural tokens ──────────────────────────────────────
|
|
700
|
+
if (token.tokenType === RdfToken.LCURLY) {
|
|
701
|
+
this.handleOpenBrace(ctx, tokens, i + 1);
|
|
702
|
+
ctx.lastToken = token;
|
|
703
|
+
ctx.lastNonWsToken = token;
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
if (token.tokenType === RdfToken.RCURLY) {
|
|
707
|
+
this.handleCloseBrace(ctx);
|
|
708
|
+
ctx.lastToken = token;
|
|
709
|
+
ctx.lastNonWsToken = token;
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
if (token.tokenType === RdfToken.PERIOD) {
|
|
713
|
+
this.handleSparqlPeriod(ctx, nextToken);
|
|
714
|
+
ctx.lastToken = token;
|
|
715
|
+
ctx.lastNonWsToken = token;
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
if (token.tokenType === RdfToken.SEMICOLON) {
|
|
719
|
+
this.handleSparqlSemicolon(ctx);
|
|
720
|
+
ctx.lastToken = token;
|
|
721
|
+
ctx.lastNonWsToken = token;
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
if (token.tokenType === RdfToken.COMMA) {
|
|
725
|
+
this.handleSparqlComma(ctx, nextToken);
|
|
726
|
+
ctx.lastToken = token;
|
|
727
|
+
ctx.lastNonWsToken = token;
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
if (token.tokenType === RdfToken.LPARENT || token.tokenType === RdfToken.LBRACKET) {
|
|
731
|
+
this.handleSparqlOpenParen(ctx, token, tokens, i);
|
|
732
|
+
ctx.lastToken = token;
|
|
733
|
+
ctx.lastNonWsToken = token;
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
if (token.tokenType === RdfToken.RPARENT || token.tokenType === RdfToken.RBRACKET) {
|
|
737
|
+
this.handleSparqlCloseParen(ctx, token);
|
|
738
|
+
ctx.lastToken = token;
|
|
739
|
+
ctx.lastNonWsToken = token;
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
// PREFIX/BASE IRI completion
|
|
743
|
+
if (ctx.inPrefix && (token.tokenType === RdfToken.IRIREF || token.tokenType === RdfToken.IRIREF_ABS)) {
|
|
744
|
+
this.handleSparqlPrefixIri(ctx, value);
|
|
745
|
+
ctx.lastToken = token;
|
|
746
|
+
ctx.lastNonWsToken = token;
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
// Triple position tracking
|
|
750
|
+
this.handleTriplePosition(ctx, token, tokens, i, prevWasComment);
|
|
751
|
+
// Line wrapping
|
|
752
|
+
this.handleLineWrapping(ctx, value);
|
|
753
|
+
// Spacing
|
|
754
|
+
this.handleSparqlTokenSpacing(ctx, token);
|
|
755
|
+
// Output the token
|
|
756
|
+
this.addPart(ctx, value, le);
|
|
757
|
+
ctx.needsSpace = true;
|
|
758
|
+
ctx.lastToken = token;
|
|
759
|
+
ctx.lastNonWsToken = token;
|
|
760
|
+
}
|
|
761
|
+
return { output: ctx.parts.join('').trim() };
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
//# sourceMappingURL=formatter.js.map
|