@matdata/sparql-formatter 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Matdata
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,245 @@
1
+ # SPARQL Formatter
2
+
3
+ ### A SPARQL 1.2 formatter that keeps your comments where you put them
4
+
5
+ [![Test](https://github.com/Matdata-eu/sparql-formatter/actions/workflows/test.yml/badge.svg)](https://github.com/Matdata-eu/sparql-formatter/actions/workflows/test.yml)
6
+ [![npm version](https://img.shields.io/npm/v/@matdata/sparql-formatter)](https://www.npmjs.com/package/@matdata/sparql-formatter)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ `@matdata/sparql-formatter` pretty-prints SPARQL queries and updates. It is the formatter of
10
+ [MatGUI](https://github.com/Matdata-eu/MatGUI) and a drop-in replacement for
11
+ [sparql-formatter](https://github.com/sparqling/sparql-formatter) (`spfmt`), with:
12
+
13
+ - **SPARQL 1.2** — `VERSION`, triple terms `<<( s p o )>>`, reified triples `<< s p o ~ r >>`, reifiers and
14
+ annotations `{| ... |}`, base direction `"x"@ar--rtl`, and the new functions (`LANGDIR`, `STRLANGDIR`,
15
+ `hasLANG`, `hasLANGDIR`, `isTRIPLE`, `TRIPLE`, `SUBJECT`, `PREDICATE`, `OBJECT`). SPARQL 1.0 and 1.1 are
16
+ fully supported too.
17
+ - **Comments that stay in place** — every comment is kept next to the code it belongs to, including comments
18
+ inside empty groups, between predicates, in expressions and at the end of the query
19
+ ([sparqling/sparql-formatter#30](https://github.com/sparqling/sparql-formatter/issues/30)).
20
+ - **Safe output** — formatting never changes the meaning of a query and running it twice gives the same
21
+ result. This is tested on the complete W3C SPARQL 1.0, 1.1 and 1.2 test suites, also with comments inserted
22
+ between every pair of tokens.
23
+ - **Zero dependencies**, ESM + CommonJS + a browser bundle, TypeScript types and a CLI.
24
+
25
+ 🌐 **Try it**: [playground](https://matdata-eu.github.io/sparql-formatter/)
26
+
27
+ ## Example
28
+
29
+ ```sparql
30
+ #comment 1
31
+ PREFIX : <http://example.org/>
32
+ select * where { :alice :knows :bob ~:claim1 {| :source ?doc ; :certainty 0.9 |} .
33
+ graph ?g {
34
+ #comment 2
35
+ }
36
+ ?city :type :City; # a city
37
+ :country :Belgium ; :population ?pop
38
+ optional { ?city :name ?name } filter(?pop > 10000) } order by desc(?pop) limit 10
39
+ ```
40
+
41
+ becomes
42
+
43
+ ```sparql
44
+ #comment 1
45
+ PREFIX : <http://example.org/>
46
+
47
+ SELECT *
48
+ WHERE {
49
+ :alice :knows :bob ~ :claim1 {| :source ?doc ; :certainty 0.9 |} .
50
+ GRAPH ?g {
51
+ #comment 2
52
+ }
53
+ ?city :type :City ; # a city
54
+ :country :Belgium ;
55
+ :population ?pop .
56
+ OPTIONAL {
57
+ ?city :name ?name .
58
+ }
59
+ FILTER (?pop > 10000)
60
+ }
61
+ ORDER BY DESC(?pop)
62
+ LIMIT 10
63
+ ```
64
+
65
+ ## Installation
66
+
67
+ ```bash
68
+ npm install @matdata/sparql-formatter
69
+ ```
70
+
71
+ ## Usage
72
+
73
+ ### JavaScript / TypeScript
74
+
75
+ ```js
76
+ import { format } from "@matdata/sparql-formatter";
77
+
78
+ const pretty = format("select * where {?s ?p ?o}");
79
+ // SELECT *
80
+ // WHERE {
81
+ // ?s ?p ?o .
82
+ // }
83
+
84
+ format(query, { indent: 4, compact: true });
85
+ ```
86
+
87
+ CommonJS works too: `const { format } = require("@matdata/sparql-formatter");`
88
+
89
+ `format` throws a `SparqlSyntaxError` (with `line`, `column` and `offset`) when the input is not valid SPARQL:
90
+
91
+ ```js
92
+ import { format, isValid, SparqlSyntaxError } from "@matdata/sparql-formatter";
93
+
94
+ try {
95
+ format("SELECT * WHERE { ?s ?p }");
96
+ } catch (e) {
97
+ if (e instanceof SparqlSyntaxError) console.log(e.line, e.column, e.message);
98
+ // 1 24 "Expected an RDF term or a variable but found '}' (line 1, column 24)"
99
+ }
100
+
101
+ isValid("SELECT * {}"); // true
102
+ ```
103
+
104
+ ### Drop-in replacement for `sparql-formatter`
105
+
106
+ The package exports an `spfmt` object with the same `format(query, formattingMode, indentDepth)` signature as
107
+ [sparql-formatter](https://github.com/sparqling/sparql-formatter), so switching is a one-line change:
108
+
109
+ ```diff
110
+ - import { spfmt } from "sparql-formatter";
111
+ + import { spfmt } from "@matdata/sparql-formatter";
112
+
113
+ spfmt.format(query); // formattingMode "default"
114
+ spfmt.format(query, "compact");
115
+ spfmt.format(query, "default", 4);
116
+ ```
117
+
118
+ The `turtle` and `jsonld` modes of sparql-formatter are not supported; use `parse()` to get the syntax tree.
119
+
120
+ ### In the browser
121
+
122
+ ```html
123
+ <script src="https://cdn.jsdelivr.net/npm/@matdata/sparql-formatter/dist/spfmt.min.js"></script>
124
+ <script>
125
+ spfmt.format("select * where {?s ?p ?o}");
126
+ sparqlFormatter.format("select * where {?s ?p ?o}", { indent: 4 }); // full API
127
+ </script>
128
+ ```
129
+
130
+ Or as an ES module: `import { format } from "https://cdn.jsdelivr.net/npm/@matdata/sparql-formatter/+esm";`
131
+
132
+ ### Command line
133
+
134
+ ```bash
135
+ npx @matdata/sparql-formatter query.rq # print the formatted query
136
+ cat query.rq | npx @matdata/sparql-formatter # read from stdin
137
+ npx @matdata/sparql-formatter --write *.rq *.ru # format files in place
138
+ npx @matdata/sparql-formatter --check *.rq # exit code 1 if a file isn't formatted (for CI)
139
+ ```
140
+
141
+ Run `sparql-formatter --help` for all options (`--indent`, `--keyword-case`, `--function-case`, `--no-align`,
142
+ `--no-blank-lines`, `--compact`, `--line-width`).
143
+
144
+ ## Options
145
+
146
+ | Option | Default | Description |
147
+ | -------------------- | ------------ | ------------------------------------------------------------------------------------------------ |
148
+ | `indent` | `2` | Number of spaces, or the indent string itself (e.g. `"\t"`). |
149
+ | `keywordCase` | `"upper"` | Case of keywords (`SELECT`, `WHERE`, `OPTIONAL`, ...): `"upper"`, `"lower"` or `"preserve"`. |
150
+ | `functionCase` | `"preserve"` | Case of built-in function names (`regex`, `STR`, `COUNT`, ...): `"upper"`, `"lower"`, `"preserve"`. |
151
+ | `alignPredicates` | `true` | Align the predicates of a subject under its first predicate. When `false`, indent them instead. |
152
+ | `preserveBlankLines` | `true` | Keep (at most one) blank line where the query has blank lines between statements. |
153
+ | `compact` | `false` | Put group patterns with a single triple on one line: `OPTIONAL { ?s :p ?o }`. |
154
+ | `lineWidth` | `100` | Line width used by `compact` and to wrap long object and `VALUES` lists. |
155
+ | `insertWhere` | `true` | Write the optional `WHERE` keyword of `SELECT`, `CONSTRUCT` and `DESCRIBE` queries. |
156
+
157
+ ## Formatting style
158
+
159
+ - Keywords are upper case; prefixed names, IRIs, variables and literals are written exactly as in the input.
160
+ - The prologue (`BASE`, `PREFIX`, `VERSION`) is followed by a blank line.
161
+ - Each clause (`SELECT`, `FROM`, `WHERE`, `GROUP BY`, `HAVING`, `ORDER BY`, `LIMIT`, `OFFSET`, `VALUES`) starts
162
+ on a new line; every pattern in a group gets its own line.
163
+ - Triple patterns end with ` .`, predicate lists with ` ;` are aligned, and objects are separated by `, `.
164
+ - The optional `.` after `OPTIONAL { }`, `FILTER`, ... and superfluous `;` are removed; their comments are kept.
165
+ - Long object lists and `VALUES` lists are wrapped, one item per line.
166
+
167
+ ### Comments
168
+
169
+ Comments are attached to the code around them:
170
+
171
+ - a comment at the end of a line stays at the end of that line;
172
+ - a comment on its own line stays on its own line, before the code that follows it, at that code's indentation;
173
+ - comments before a closing `}` stay inside the block;
174
+ - blank lines before comments are kept.
175
+
176
+ If a comment ends up in the middle of an expression, the formatter continues the expression on the next line
177
+ rather than moving the comment. The formatter never drops a comment: if it can't place one, it throws an error
178
+ instead of returning a query without it.
179
+
180
+ ## What is checked
181
+
182
+ The parser implements the complete [SPARQL 1.2 grammar](https://www.w3.org/TR/sparql12-query/#sparqlGrammar)
183
+ for queries and updates, including the grammar notes (no variables in `INSERT DATA`, no blank nodes in
184
+ `DELETE`, the number of values in `VALUES` rows, no reifiers after property paths, ...). It does not check
185
+ rules that go beyond the grammar, such as variable scoping in `SELECT` and `BIND`, grouping rules of
186
+ aggregates, or blank node label reuse across basic graph patterns: formatting such a query works.
187
+
188
+ ## API
189
+
190
+ | Export | Description |
191
+ | ---------------------------- | ---------------------------------------------------------------------- |
192
+ | `format(query, options?)` | Format a query or update. Also the default export. |
193
+ | `isValid(query)` | `true` when the query is syntactically valid SPARQL 1.2. |
194
+ | `parse(query)` | Parse into a concrete syntax tree (`Query` or `Update`). |
195
+ | `formatAst(ast, options?)` | Format a tree returned by `parse`. |
196
+ | `tokenize(query)` | The tokens of a query, with the comments attached to them. |
197
+ | `spfmt` | `{ format, parse, tokenize }`, compatible with `sparql-formatter`. |
198
+ | `SparqlSyntaxError` | Error thrown for invalid input (`line`, `column`, `offset`, `expected`). |
199
+
200
+ ## Development
201
+
202
+ ```bash
203
+ npm install
204
+ npm test # unit tests + W3C test suites (Node 22+, runs the TypeScript sources directly)
205
+ npm run typecheck
206
+ npm run lint # prettier --check
207
+ npm run build # dist/: ESM, CommonJS, browser bundle, CLI and type declarations
208
+ npm run test:dist # smoke test of the built package
209
+ ```
210
+
211
+ The source is in `src/`: `lexer.ts` (tokens and comments), `parser.ts` (recursive-descent parser),
212
+ `printer.ts` (layout) and `writer.ts` (output buffer that places the comments).
213
+
214
+ The W3C test queries in `test/w3c` are imported from [w3c/rdf-tests](https://github.com/w3c/rdf-tests) with:
215
+
216
+ ```bash
217
+ git clone --depth 1 https://github.com/w3c/rdf-tests
218
+ node scripts/import-w3c-tests.mjs rdf-tests
219
+ ```
220
+
221
+ ## Releasing
222
+
223
+ Releases are published to npm by the [publish workflow](.github/workflows/publish.yml) when a GitHub release is
224
+ published. The version is taken from the release tag (`v1.2.3` → `1.2.3`; a pre-release such as `v1.3.0-beta.1`
225
+ is published with the `next` dist-tag).
226
+
227
+ The workflow uses [npm trusted publishing](https://docs.npmjs.com/trusted-publishers): there is no npm token in
228
+ the repository. One-time setup on [npmjs.com](https://www.npmjs.com/package/@matdata/sparql-formatter) →
229
+ **Settings** → **Trusted Publisher** → **GitHub Actions**:
230
+
231
+ - Organization or user: `Matdata-eu`
232
+ - Repository: `sparql-formatter`
233
+ - Workflow filename: `publish.yml`
234
+
235
+ npm only lets you add a trusted publisher to a package that already exists, so the very first version has to be
236
+ published once by hand (`npm run build && npm publish --access public`) by a member of the `@matdata` npm
237
+ organization.
238
+
239
+ The [playground](https://matdata-eu.github.io/sparql-formatter/) is deployed to GitHub Pages on every push to
240
+ `main` (repository **Settings** → **Pages** → Source: **GitHub Actions**).
241
+
242
+ ## License
243
+
244
+ [MIT](LICENSE). The test queries in `test/w3c` come from the W3C test suites and are distributed under the
245
+ [W3C test suite licenses](https://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html).
package/dist/ast.d.ts ADDED
@@ -0,0 +1,447 @@
1
+ /**
2
+ * Concrete syntax tree for SPARQL 1.2 queries and updates.
3
+ *
4
+ * The tree keeps a reference to every source token (keywords, punctuation,
5
+ * terms) so the printer can re-emit the comments attached to them and keep
6
+ * the original spelling of terms.
7
+ */
8
+ import type { Token } from "./lexer.js";
9
+ /**
10
+ * A term printed as the concatenation of its tokens: an IRI, a variable, a
11
+ * literal (`"x"@en`, `"1"^^xsd:int`), a signed number (`-1`), a blank node,
12
+ * `a`, `true`, `NIL` (`()`), `ANON` (`[]`), `UNDEF`.
13
+ */
14
+ export interface Term {
15
+ type: "Term";
16
+ tokens: Token[];
17
+ }
18
+ /** `<<( s p o )>>` */
19
+ export interface TripleTerm {
20
+ type: "TripleTerm";
21
+ open: Token;
22
+ subject: Node;
23
+ predicate: Term;
24
+ object: Node;
25
+ close: Token;
26
+ }
27
+ /** `<< s p o ~ r >>` */
28
+ export interface ReifiedTriple {
29
+ type: "ReifiedTriple";
30
+ open: Token;
31
+ subject: Node;
32
+ predicate: Term;
33
+ object: Node;
34
+ reifier: Reifier | null;
35
+ close: Token;
36
+ }
37
+ /** `~ id` */
38
+ export interface Reifier {
39
+ type: "Reifier";
40
+ tilde: Token;
41
+ id: Term | null;
42
+ }
43
+ /** `{| p o ; ... |}` */
44
+ export interface AnnotationBlock {
45
+ type: "AnnotationBlock";
46
+ open: Token;
47
+ properties: PropertyList;
48
+ close: Token;
49
+ }
50
+ /** `( a b c )` */
51
+ export interface Collection {
52
+ type: "Collection";
53
+ open: Token;
54
+ items: Node[];
55
+ close: Token;
56
+ }
57
+ /** `[ p o ; ... ]` */
58
+ export interface BlankNodePropertyList {
59
+ type: "BlankNodePropertyList";
60
+ open: Token;
61
+ properties: PropertyList;
62
+ close: Token;
63
+ }
64
+ export interface ObjectEntry {
65
+ node: Node;
66
+ annotations: (Reifier | AnnotationBlock)[];
67
+ /** The `,` that follows this object, if any. */
68
+ comma: Token | null;
69
+ }
70
+ export interface PropertyEntry {
71
+ verb: Node;
72
+ objects: ObjectEntry[];
73
+ /** The `;` tokens that follow this entry (`; ;` is legal). */
74
+ semicolons: Token[];
75
+ }
76
+ export interface PropertyList {
77
+ type: "PropertyList";
78
+ /** `;` tokens that appear before the first entry are not legal; entries only. */
79
+ entries: PropertyEntry[];
80
+ }
81
+ /** A subject with its property list: `?s :p ?o ; :q ?r` */
82
+ export interface Triples {
83
+ type: "Triples";
84
+ subject: Node;
85
+ properties: PropertyList | null;
86
+ }
87
+ export interface PathAlternative {
88
+ type: "PathAlternative";
89
+ items: Node[];
90
+ separators: Token[];
91
+ }
92
+ export interface PathSequence {
93
+ type: "PathSequence";
94
+ items: Node[];
95
+ separators: Token[];
96
+ }
97
+ export interface PathInverse {
98
+ type: "PathInverse";
99
+ caret: Token;
100
+ item: Node;
101
+ }
102
+ export interface PathModified {
103
+ type: "PathModified";
104
+ item: Node;
105
+ modifier: Token;
106
+ }
107
+ export interface PathNegated {
108
+ type: "PathNegated";
109
+ bang: Token;
110
+ item: Node;
111
+ }
112
+ /** `( path )` in a property path, also `!( a | ^b )` */
113
+ export interface PathGroup {
114
+ type: "PathGroup";
115
+ open: Token;
116
+ path: Node | null;
117
+ close: Token;
118
+ }
119
+ export interface Binary {
120
+ type: "Binary";
121
+ left: Node;
122
+ operator: Token;
123
+ right: Node;
124
+ }
125
+ /** `x IN (...)` / `x NOT IN (...)` */
126
+ export interface InExpression {
127
+ type: "In";
128
+ expression: Node;
129
+ not: Token | null;
130
+ in: Token;
131
+ list: ExpressionList;
132
+ }
133
+ export interface Unary {
134
+ type: "Unary";
135
+ operator: Token;
136
+ expression: Node;
137
+ }
138
+ export interface Bracketed {
139
+ type: "Bracketed";
140
+ open: Token;
141
+ expression: Node;
142
+ close: Token;
143
+ }
144
+ /** `( e1, e2 )` or `()` */
145
+ export interface ExpressionList {
146
+ type: "ExpressionList";
147
+ open: Token;
148
+ items: Node[];
149
+ commas: Token[];
150
+ close: Token;
151
+ }
152
+ /** A built-in call, aggregate or function call. */
153
+ export interface Call {
154
+ type: "Call";
155
+ /** A NAME token for built-ins, a Term for IRI function calls. */
156
+ name: Token | Term;
157
+ builtin: boolean;
158
+ /** The opening parenthesis; a call written as `NOW()` has no args. */
159
+ open: Token;
160
+ distinct: Token | null;
161
+ args: Node[];
162
+ commas: Token[];
163
+ /** GROUP_CONCAT separator: `; SEPARATOR = "x"` */
164
+ separator: {
165
+ semicolon: Token;
166
+ keyword: Token;
167
+ equals: Token;
168
+ value: Term;
169
+ } | null;
170
+ close: Token;
171
+ }
172
+ /** `EXISTS { }` / `NOT EXISTS { }` */
173
+ export interface Exists {
174
+ type: "Exists";
175
+ not: Token | null;
176
+ keyword: Token;
177
+ group: GroupGraphPattern;
178
+ }
179
+ export interface GroupGraphPattern {
180
+ type: "GroupGraphPattern";
181
+ open: Token;
182
+ subSelect: SubSelect | null;
183
+ items: PatternItem[];
184
+ close: Token;
185
+ }
186
+ export interface PatternItem {
187
+ node: Node;
188
+ /** The `.` that follows the item, if any. */
189
+ dot: Token | null;
190
+ }
191
+ export interface Union {
192
+ type: "Union";
193
+ groups: GroupGraphPattern[];
194
+ keywords: Token[];
195
+ }
196
+ export interface Optional {
197
+ type: "Optional";
198
+ keyword: Token;
199
+ group: GroupGraphPattern;
200
+ }
201
+ export interface Minus {
202
+ type: "Minus";
203
+ keyword: Token;
204
+ group: GroupGraphPattern;
205
+ }
206
+ export interface GraphPattern {
207
+ type: "Graph";
208
+ keyword: Token;
209
+ name: Term;
210
+ group: GroupGraphPattern;
211
+ }
212
+ export interface Service {
213
+ type: "Service";
214
+ keyword: Token;
215
+ silent: Token | null;
216
+ name: Term;
217
+ group: GroupGraphPattern;
218
+ }
219
+ export interface Filter {
220
+ type: "Filter";
221
+ keyword: Token;
222
+ constraint: Node;
223
+ }
224
+ export interface Bind {
225
+ type: "Bind";
226
+ keyword: Token;
227
+ open: Token;
228
+ expression: Node;
229
+ as: Token;
230
+ variable: Term;
231
+ close: Token;
232
+ }
233
+ export interface Values {
234
+ type: "Values";
235
+ keyword: Token;
236
+ block: DataBlock;
237
+ }
238
+ export interface DataBlockRow {
239
+ /** `( v1 v2 )`; for NIL rows `open`/`close` are the `(` `)` tokens and values is empty. */
240
+ open: Token;
241
+ values: Node[];
242
+ close: Token;
243
+ }
244
+ export interface DataBlock {
245
+ type: "DataBlock";
246
+ /** Single variable form: `?x { ... }` */
247
+ variable: Term | null;
248
+ /** Multi-variable form: `( ?a ?b ) { ... }` */
249
+ variables: {
250
+ open: Token;
251
+ vars: Term[];
252
+ close: Token;
253
+ } | null;
254
+ open: Token;
255
+ /** Values of the single-variable form. */
256
+ values: Node[];
257
+ /** Rows of the multi-variable form. */
258
+ rows: DataBlockRow[];
259
+ close: Token;
260
+ }
261
+ export interface PrologueDecl {
262
+ type: "Base" | "Prefix" | "Version";
263
+ keyword: Token;
264
+ /** PREFIX only */
265
+ prefix: Token | null;
266
+ value: Token;
267
+ }
268
+ export interface Projection {
269
+ type: "Projection";
270
+ open: Token;
271
+ expression: Node;
272
+ as: Token | null;
273
+ variable: Term | null;
274
+ close: Token;
275
+ }
276
+ export interface SelectClause {
277
+ type: "SelectClause";
278
+ keyword: Token;
279
+ modifier: Token | null;
280
+ star: Token | null;
281
+ items: (Term | Projection)[];
282
+ }
283
+ export interface DatasetClause {
284
+ type: "DatasetClause";
285
+ from: Token;
286
+ named: Token | null;
287
+ iri: Term;
288
+ }
289
+ export interface WhereClause {
290
+ keyword: Token | null;
291
+ group: GroupGraphPattern;
292
+ }
293
+ export interface OrderCondition {
294
+ type: "OrderCondition";
295
+ direction: Token | null;
296
+ expression: Node;
297
+ }
298
+ export interface SolutionModifier {
299
+ groupBy: {
300
+ group: Token;
301
+ by: Token;
302
+ conditions: Node[];
303
+ } | null;
304
+ having: {
305
+ keyword: Token;
306
+ conditions: Node[];
307
+ } | null;
308
+ orderBy: {
309
+ order: Token;
310
+ by: Token;
311
+ conditions: Node[];
312
+ } | null;
313
+ /** LIMIT and OFFSET in source order */
314
+ limitOffset: {
315
+ keyword: Token;
316
+ value: Token;
317
+ }[];
318
+ }
319
+ export interface SelectQuery {
320
+ type: "Select";
321
+ select: SelectClause;
322
+ datasets: DatasetClause[];
323
+ where: WhereClause;
324
+ modifiers: SolutionModifier;
325
+ }
326
+ export interface SubSelect extends Omit<SelectQuery, "type"> {
327
+ type: "SubSelect";
328
+ values: Values | null;
329
+ }
330
+ /** Triples inside `{ }` of a CONSTRUCT template or quad data */
331
+ export interface TriplesTemplate {
332
+ type: "TriplesTemplate";
333
+ open: Token;
334
+ items: PatternItem[];
335
+ close: Token;
336
+ }
337
+ export interface ConstructQuery {
338
+ type: "Construct";
339
+ keyword: Token;
340
+ template: TriplesTemplate | null;
341
+ datasets: DatasetClause[];
342
+ /** Full form: WHERE clause. Short form (`CONSTRUCT WHERE { triples }`): `where.keyword` + `shortTemplate` */
343
+ where: WhereClause | null;
344
+ shortForm: {
345
+ keyword: Token;
346
+ template: TriplesTemplate;
347
+ } | null;
348
+ modifiers: SolutionModifier;
349
+ }
350
+ export interface DescribeQuery {
351
+ type: "Describe";
352
+ keyword: Token;
353
+ star: Token | null;
354
+ items: Term[];
355
+ datasets: DatasetClause[];
356
+ where: WhereClause | null;
357
+ modifiers: SolutionModifier;
358
+ }
359
+ export interface AskQuery {
360
+ type: "Ask";
361
+ keyword: Token;
362
+ datasets: DatasetClause[];
363
+ where: WhereClause;
364
+ modifiers: SolutionModifier;
365
+ }
366
+ export type QueryForm = SelectQuery | ConstructQuery | DescribeQuery | AskQuery;
367
+ export interface Query {
368
+ type: "Query";
369
+ prologue: PrologueDecl[];
370
+ form: QueryForm;
371
+ values: Values | null;
372
+ eof: Token;
373
+ }
374
+ /** Keyword/IRI sequences such as `GRAPH <g>`, `DEFAULT`, `SILENT` */
375
+ export interface Words {
376
+ type: "Words";
377
+ tokens: (Token | Term)[];
378
+ }
379
+ export interface QuadsGraph {
380
+ type: "QuadsGraph";
381
+ keyword: Token;
382
+ name: Term;
383
+ template: TriplesTemplate;
384
+ }
385
+ export interface Load {
386
+ type: "Load";
387
+ keyword: Token;
388
+ silent: Token | null;
389
+ iri: Term;
390
+ into: Words | null;
391
+ }
392
+ /** CLEAR, DROP, CREATE */
393
+ export interface GraphManagement {
394
+ type: "GraphManagement";
395
+ keyword: Token;
396
+ silent: Token | null;
397
+ target: Words;
398
+ }
399
+ /** ADD, MOVE, COPY */
400
+ export interface GraphTransfer {
401
+ type: "GraphTransfer";
402
+ keyword: Token;
403
+ silent: Token | null;
404
+ from: Words;
405
+ to: Token;
406
+ target: Words;
407
+ }
408
+ /** INSERT DATA, DELETE DATA, DELETE WHERE */
409
+ export interface QuadDataOperation {
410
+ type: "QuadData";
411
+ keywords: [Token, Token];
412
+ quads: TriplesTemplate;
413
+ }
414
+ export interface Modify {
415
+ type: "Modify";
416
+ with: {
417
+ keyword: Token;
418
+ iri: Term;
419
+ } | null;
420
+ delete: {
421
+ keyword: Token;
422
+ quads: TriplesTemplate;
423
+ } | null;
424
+ insert: {
425
+ keyword: Token;
426
+ quads: TriplesTemplate;
427
+ } | null;
428
+ using: {
429
+ keyword: Token;
430
+ named: Token | null;
431
+ iri: Term;
432
+ }[];
433
+ where: WhereClause;
434
+ }
435
+ export type UpdateOperation = Load | GraphManagement | GraphTransfer | QuadDataOperation | Modify;
436
+ export interface UpdatePart {
437
+ prologue: PrologueDecl[];
438
+ operation: UpdateOperation | null;
439
+ semicolon: Token | null;
440
+ }
441
+ export interface Update {
442
+ type: "Update";
443
+ parts: UpdatePart[];
444
+ eof: Token;
445
+ }
446
+ export type Node = Term | TripleTerm | ReifiedTriple | Reifier | AnnotationBlock | Collection | BlankNodePropertyList | PropertyList | Triples | PathAlternative | PathSequence | PathInverse | PathModified | PathNegated | PathGroup | Binary | InExpression | Unary | Bracketed | ExpressionList | Call | Exists | GroupGraphPattern | Union | Optional | Minus | GraphPattern | Service | Filter | Bind | Values | DataBlock | Projection | OrderCondition | SubSelect | TriplesTemplate | QuadsGraph;
447
+ export type Ast = Query | Update;