1- import type { Range } from '@traqula/core' ;
21import { GeneratorBuilder , RangeArithmetic } from '@traqula/core' ;
3- import type { PatternBgp , SparqlContext , Triple } from '@traqula/rules-sparql-1-1' ;
2+ import type { PatternBgp , SparqlContext , TripleNesting } from '@traqula/rules-sparql-1-1' ;
43import { CommonIRIs , TraqulaFactory , completeParseContext , lex as l , gram } from '@traqula/rules-sparql-1-1' ;
54import { describe , it } from 'vitest' ;
65import { objectListBuilder } from '../lib' ;
@@ -32,32 +31,31 @@ describe('ranges', () => {
3231
3332describe ( 'a SPARQL 1.1 objectList parser' , ( ) => {
3433 const F = new TraqulaFactory ( ) ;
35- const subject = F . namedNode ( 'http://example.org/subject' , undefined , F . noStringMaterialization ( ) ) ;
36- const predicate = F . namedNode ( 'http://example.org/predicate' , undefined , F . noStringMaterialization ( ) ) ;
34+ const subject = F . namedNode ( F . sourceLocationNoMaterialize ( ) , 'http://example.org/subject' ) ;
35+ const predicate = F . namedNode ( F . sourceLocationNoMaterialize ( ) , 'http://example.org/predicate' ) ;
3736
38- function generate ( ast : PatternBgp , skipRanges : Range [ ] ) : string {
37+ function generate ( ast : PatternBgp , origSource : string ) : string {
3938 const generator = GeneratorBuilder . createBuilder ( [
4039 gram . triplesBlock ,
41- gram . varOrTerm ,
40+ gram . graphNode ,
4241 gram . graphTerm ,
4342 gram . var_ ,
4443 gram . rdfLiteral ,
45- gram . string ,
4644 gram . path ,
45+ gram . varOrTerm ,
46+ gram . triplesNode ,
47+ gram . collection ,
48+ gram . blankNodePropertyList ,
4749 gram . blankNode ,
4850 gram . iri ,
4951 gram . iriFull ,
5052 gram . prefixedName ,
5153 ] ) . build ( ) ;
52- return generator . triplesBlock ( ast , { factory : F , skipRanges } , undefined ) ;
54+ return generator . triplesBlock ( ast , { factory : F , origSource } , undefined ) ;
5355 }
5456
55- function toBgp ( query : string , triples : Triple [ ] ) : PatternBgp {
56- return F . patternBgp ( triples , {
57- start : 0 ,
58- end : query . length - 1 ,
59- source : query ,
60- } ) ;
57+ function toBgp ( query : string , triples : TripleNesting [ ] ) : PatternBgp {
58+ return F . patternBgp ( triples , F . sourceLocationSource ( 0 , query . length ) ) ;
6159 }
6260
6361 function parse ( query : string , context : Partial < SparqlContext > ) : PatternBgp {
@@ -72,7 +70,7 @@ describe('a SPARQL 1.1 objectList parser', () => {
7270 const firstTriple = F . triple (
7371 subject ,
7472 predicate ,
75- F . namedNode ( 'dust-in-the-wind' , undefined , { start : 0 , end : 18 } ) ,
73+ F . namedNode ( F . sourceLocationSource ( 0 , 18 ) , 'dust-in-the-wind' ) ,
7674 ) ;
7775
7876 const tests : { query : string ; ast : PatternBgp | null ; name : string } [ ] = [ {
@@ -89,7 +87,7 @@ describe('a SPARQL 1.1 objectList parser', () => {
8987 get ast ( ) {
9088 return toBgp ( this . query , [
9189 firstTriple ,
92- F . triple ( subject , predicate , F . namedNode ( 'right-now' , undefined , { start : 29 , end : 40 } ) ) ,
90+ F . triple ( subject , predicate , F . namedNode ( F . sourceLocationSource ( 29 , 40 ) , 'right-now' ) ) ,
9391 ] ) ;
9492 } ,
9593 } , {
@@ -100,8 +98,8 @@ describe('a SPARQL 1.1 objectList parser', () => {
10098 get ast ( ) {
10199 return toBgp ( this . query , [
102100 firstTriple ,
103- F . triple ( subject , predicate , F . namedNode ( 'right-now' , undefined , { start : 29 , end : 40 } ) ) ,
104- F . triple ( subject , predicate , F . literalTerm ( 'alegria' , undefined , { start : 42 , end : 55 } ) ) ,
101+ F . triple ( subject , predicate , F . namedNode ( F . sourceLocationSource ( 29 , 40 ) , 'right-now' ) ) ,
102+ F . triple ( subject , predicate , F . literalTerm ( F . sourceLocationSource ( 42 , 55 ) , 'alegria' ) ) ,
105103 ] ) ;
106104 } ,
107105 } , {
@@ -112,7 +110,7 @@ describe('a SPARQL 1.1 objectList parser', () => {
112110 get ast ( ) {
113111 return toBgp ( this . query , [
114112 firstTriple ,
115- F . triple ( subject , predicate , F . blankNode ( undefined , { start : 29 , end : 31 } ) ) ,
113+ F . triple ( subject , predicate , F . blankNode ( undefined , F . sourceLocationSource ( 29 , 31 ) ) ) ,
116114 ] ) ;
117115 } ,
118116 } , {
@@ -121,138 +119,155 @@ describe('a SPARQL 1.1 objectList parser', () => {
121119 [ <right-now> "alegria" ]
122120 ` ,
123121 get ast ( ) {
124- const blankNode = F . blankNode ( undefined , { start : 29 , end : 54 } ) ;
122+ const blankNode = F . blankNode ( undefined , F . sourceLocationNoMaterialize ( ) ) ;
125123 return toBgp ( this . query , [
126124 firstTriple ,
127- F . triple ( subject , predicate , blankNode ) ,
128- F . triple (
125+ F . triple ( subject , predicate , F . tripleCollectionBlankNodeProperties (
129126 blankNode ,
130- F . namedNode ( 'right-now' , undefined , { start : 31 , end : 42 } ) ,
131- F . literalTerm ( 'alegria' , undefined , { start : 43 , end : 52 } ) ,
132- ) ,
127+ [ F . triple (
128+ blankNode ,
129+ F . namedNode ( F . sourceLocationSource ( 31 , 42 ) , 'right-now' ) ,
130+ F . literalTerm ( F . sourceLocationSource ( 43 , 52 ) , 'alegria' ) ,
131+ ) ] ,
132+ F . sourceLocationSource ( 29 , 54 ) ,
133+ ) ) ,
133134 ] ) ;
134135 } ,
135136 } , {
136137 name : 'nested blankNodePropertyList' ,
137- query : `<dust-in-the-wind> ,
138+ query : `<dust-in-the-wind> ,
138139 [
139140 <right-now> "alegria" ;
140141 a <http://example.org/Class> , <apple>, [ a <banana> ]
141142 ]
142143` ,
143144 get ast ( ) {
144- const outer = F . blankNode ( undefined , { start : 26 , end : 128 } ) ;
145- const outerA = F . namedNode ( CommonIRIs . TYPE , undefined , { start : 68 , end : 69 } ) ;
146- const inner = F . blankNode ( undefined , { start : 108 , end : 122 } ) ;
147- return toBgp ( this . query , [
148- firstTriple ,
149- F . triple ( subject , predicate , outer ) ,
145+ const outerBlank = F . blankNode ( undefined , F . sourceLocationNoMaterialize ( ) ) ;
146+ const outerA = F . namedNode ( F . sourceLocationSource ( 67 , 68 ) , CommonIRIs . TYPE ) ;
147+ const innerBlank = F . blankNode ( undefined , F . sourceLocationNoMaterialize ( ) ) ;
148+
149+ const propertyTriples = [
150150 F . triple (
151- outer ,
152- F . namedNode ( 'right-now' , undefined , { start : 36 , end : 47 } ) ,
153- F . literalTerm ( 'alegria' , undefined , { start : 48 , end : 57 } ) ,
151+ outerBlank ,
152+ F . namedNode ( F . sourceLocationSource ( 35 , 46 ) , 'right-now' ) ,
153+ F . literalTerm ( F . sourceLocationSource ( 47 , 56 ) , 'alegria' ) ,
154154 ) ,
155155 F . triple (
156- outer ,
156+ outerBlank ,
157157 outerA ,
158- F . namedNode ( 'http://example.org/Class' , undefined , { start : 70 , end : 96 } ) ,
158+ F . namedNode ( F . sourceLocationSource ( 69 , 95 ) , 'http://example.org/Class' ) ,
159159 ) ,
160160 F . triple (
161- outer ,
161+ outerBlank ,
162162 outerA ,
163- F . namedNode ( 'apple' , undefined , { start : 99 , end : 106 } ) ,
163+ F . namedNode ( F . sourceLocationSource ( 98 , 105 ) , 'apple' ) ,
164164 ) ,
165165 F . triple (
166- outer ,
166+ outerBlank ,
167167 outerA ,
168- inner ,
169- ) ,
170- F . triple (
171- inner ,
172- F . namedNode ( CommonIRIs . TYPE , undefined , { start : 110 , end : 111 } ) ,
173- F . namedNode ( 'banana' , undefined , { start : 112 , end : 120 } ) ,
168+ F . tripleCollectionBlankNodeProperties ( innerBlank , [ F . triple (
169+ innerBlank ,
170+ F . namedNode ( F . sourceLocationSource ( 109 , 110 ) , CommonIRIs . TYPE ) ,
171+ F . namedNode ( F . sourceLocationSource ( 111 , 119 ) , 'banana' ) ,
172+ ) ] , F . sourceLocationSource ( 107 , 121 ) ) ,
174173 ) ,
174+ ] ;
175+
176+ return toBgp ( this . query , [
177+ firstTriple ,
178+ F . triple ( subject , predicate , F . tripleCollectionBlankNodeProperties (
179+ outerBlank ,
180+ propertyTriples ,
181+ F . sourceLocationSource ( 25 , 127 ) ,
182+ ) ) ,
175183 ] ) ;
176184 } ,
177185 } , {
178186 name : 'propertyList with much blank and comments' ,
179- query : `<dust-in-the-wind> ,
187+ query : `<dust-in-the-wind> ,
180188 [
181- <right-now> "alegria" ; ;
189+ <right-now> "alegria" ; ;
182190 # More lines
183191 ; ;
184192 a <http://example.org/Class> , <apple>, [ a <banana> ]
185193 ]
186194` ,
187195 get ast ( ) {
188- const outer = F . blankNode ( undefined , { start : 26 , end : 164 } ) ;
189- const outerA = F . namedNode ( CommonIRIs . TYPE , undefined , { start : 104 , end : 105 } ) ;
190- const inner = F . blankNode ( undefined , { start : 144 , end : 158 } ) ;
191- return toBgp ( this . query , [
192- firstTriple ,
193- F . triple ( subject , predicate , outer ) ,
196+ const outerBlank = F . blankNode ( undefined , F . sourceLocationNoMaterialize ( ) ) ;
197+ const innerBlank = F . blankNode ( undefined , F . sourceLocationNoMaterialize ( ) ) ;
198+ const outerA = F . namedNode ( F . sourceLocationSource ( 102 , 103 ) , CommonIRIs . TYPE ) ;
199+
200+ const outer = F . tripleCollectionBlankNodeProperties ( outerBlank , [
194201 F . triple (
195- outer ,
196- F . namedNode ( 'right-now' , undefined , { start : 36 , end : 47 } ) ,
197- F . literalTerm ( 'alegria' , undefined , { start : 48 , end : 57 } ) ,
202+ outerBlank ,
203+ F . namedNode ( F . sourceLocationSource ( 35 , 46 ) , 'right-now' ) ,
204+ F . literalTerm ( F . sourceLocationSource ( 47 , 56 ) , 'alegria' ) ,
198205 ) ,
199206 F . triple (
200- outer ,
207+ outerBlank ,
201208 outerA ,
202- F . namedNode ( 'http://example.org/Class' , undefined , { start : 106 , end : 132 } ) ,
209+ F . namedNode ( F . sourceLocationSource ( 104 , 130 ) , 'http://example.org/Class' ) ,
203210 ) ,
204211 F . triple (
205- outer ,
212+ outerBlank ,
206213 outerA ,
207- F . namedNode ( 'apple' , undefined , { start : 135 , end : 142 } ) ,
214+ F . namedNode ( F . sourceLocationSource ( 133 , 140 ) , 'apple' ) ,
208215 ) ,
209216 F . triple (
210- outer ,
217+ outerBlank ,
211218 outerA ,
212- inner ,
213- ) ,
214- F . triple (
215- inner ,
216- F . namedNode ( CommonIRIs . TYPE , undefined , { start : 146 , end : 147 } ) ,
217- F . namedNode ( 'banana' , undefined , { start : 148 , end : 156 } ) ,
219+ F . tripleCollectionBlankNodeProperties ( innerBlank , [
220+ F . triple (
221+ innerBlank ,
222+ F . namedNode ( F . sourceLocationSource ( 144 , 145 ) , CommonIRIs . TYPE ) ,
223+ F . namedNode ( F . sourceLocationSource ( 147 , 154 ) , 'banana' ) ,
224+ ) ,
225+ ] , F . sourceLocationSource ( 142 , 156 ) ) ,
218226 ) ,
227+ ] , F . sourceLocationSource ( 25 , 162 ) ) ;
228+ return toBgp ( this . query , [
229+ firstTriple ,
230+ F . triple ( subject , predicate , outer ) ,
219231 ] ) ;
220232 } ,
221233 } , {
222234 name : 'empty collection' ,
223- query : `<dust-in-the-wind> ,
235+ query : `<dust-in-the-wind> ,
224236 ( )
225237` ,
226238 get ast ( ) {
227239 return toBgp ( this . query , [
228240 firstTriple ,
229- F . triple ( subject , predicate , F . namedNode ( CommonIRIs . NIL , undefined , { start : 26 , end : 29 } ) ) ,
241+ F . triple ( subject , predicate , F . namedNode ( F . sourceLocationSource ( 25 , 28 ) , CommonIRIs . NIL ) ) ,
230242 ] ) ;
231243 } ,
232244 } , {
233245 name : 'connection 3 elements' ,
234- query : `<dust-in-the-wind> ,
246+ query : `<dust-in-the-wind> ,
235247 ( <a> [] <b> )
236248` ,
237249 get ast ( ) {
238250 // Content blankNodes are created before list blankNodes
239- const emptyBlank = F . blankNode ( undefined , { start : 32 , end : 34 } ) ;
251+ const emptyBlank = F . blankNode ( undefined , F . sourceLocationSource ( 31 , 33 ) ) ;
240252
241- const outer = F . blankNode ( undefined , { start : 26 , end : 40 } ) ;
242- const first = F . namedNode ( CommonIRIs . FIRST , undefined , F . noStringMaterialization ( ) ) ;
243- const rest = F . namedNode ( CommonIRIs . REST , undefined , F . noStringMaterialization ( ) ) ;
244- const nil = F . namedNode ( CommonIRIs . NIL , undefined , F . noStringMaterialization ( ) ) ;
245- const rest1 = F . blankNode ( undefined , F . noStringMaterialization ( ) ) ;
246- const rest2 = F . blankNode ( undefined , F . noStringMaterialization ( ) ) ;
247- return toBgp ( this . query , [
248- firstTriple ,
249- F . triple ( subject , predicate , outer ) ,
250- F . triple ( outer , first , F . namedNode ( 'a' , undefined , { start : 28 , end : 31 } ) ) ,
251- F . triple ( outer , rest , rest1 ) ,
253+ const listHead = F . blankNode ( undefined , F . sourceLocationNoMaterialize ( ) ) ;
254+ const first = F . namedNode ( F . sourceLocationNoMaterialize ( ) , CommonIRIs . FIRST ) ;
255+ const rest = F . namedNode ( F . sourceLocationNoMaterialize ( ) , CommonIRIs . REST ) ;
256+ const nil = F . namedNode ( F . sourceLocationNoMaterialize ( ) , CommonIRIs . NIL ) ;
257+ const rest1 = F . blankNode ( undefined , F . sourceLocationNoMaterialize ( ) ) ;
258+ const rest2 = F . blankNode ( undefined , F . sourceLocationNoMaterialize ( ) ) ;
259+ const listWrap = F . tripleCollectionList ( listHead , [
260+ F . triple ( listHead , first , F . namedNode ( F . sourceLocationSource ( 27 , 30 ) , 'a' ) ) ,
261+ F . triple ( listHead , rest , rest1 ) ,
252262 F . triple ( rest1 , first , emptyBlank ) ,
253263 F . triple ( rest1 , rest , rest2 ) ,
254- F . triple ( rest2 , first , F . namedNode ( 'b' , undefined , { start : 35 , end : 38 } ) ) ,
264+ F . triple ( rest2 , first , F . namedNode ( F . sourceLocationSource ( 34 , 37 ) , 'b' ) ) ,
255265 F . triple ( rest2 , rest , nil ) ,
266+ ] , F . sourceLocationSource ( 25 , 39 ) ) ;
267+
268+ return toBgp ( this . query , [
269+ firstTriple ,
270+ F . triple ( subject , predicate , listWrap ) ,
256271 ] ) ;
257272 } ,
258273 } ] ;
@@ -264,7 +279,7 @@ describe('a SPARQL 1.1 objectList parser', () => {
264279 F . resetBlankNodeCounter ( ) ;
265280 expect ( res ) . toEqual ( test . ast ) ;
266281
267- const generated = generate ( res , [ ] ) ;
282+ const generated = generate ( res , test . query ) ;
268283 expect ( generated ) . toEqual ( test . query ) ;
269284 } ) ;
270285 }
@@ -276,19 +291,28 @@ describe('a SPARQL 1.1 objectList parser', () => {
276291 F . resetBlankNodeCounter ( ) ;
277292 const res = parse ( query , context ) ;
278293 F . resetBlankNodeCounter ( ) ;
279- const toSkip = res . triples [ 2 ] . object . loc ! ;
280- const alterRes : PatternBgp = {
281- ...res ,
282- triples : [
283- ...res . triples . slice ( 0 , 2 ) ,
284- F . triple (
285- res . triples [ 2 ] . subject ,
286- res . triples [ 2 ] . predicate ,
287- F . literalTerm ( 'altered' , undefined ) ,
288- ) ,
289- ] ,
290- } ;
291- expect ( generate ( alterRes , [ [ toSkip . start , toSkip . end ] ] ) ) . toEqual ( `<dust-in-the-wind> ,
294+ /* eslint-disable ts/ban-ts-comment */
295+ function alterType ( curObject : object , searchType : string , patch : ( current : object ) => object ) : object {
296+ for ( const [ key , value ] of Object . entries ( curObject ) ) {
297+ if ( value && typeof value === 'object' ) {
298+ ( < Record < string , unknown > > curObject ) [ key ] = alterType ( value , searchType , patch ) ;
299+ }
300+ }
301+ if ( ( < { type ?: unknown } > curObject ) . type === searchType ) {
302+ return patch ( curObject ) ;
303+ }
304+ return curObject ;
305+ }
306+ const alterRes = < PatternBgp > alterType ( res , 'term' , ( cur ) => {
307+ if ( F . isTerm ( cur ) && F . isTermLiteral ( cur ) && cur . value === 'alegria' ) {
308+ // @ts -expect-error
309+ return F . literalTerm ( F . sourceLocationNodeReplace ( cur . loc . start , cur . loc . end ) , 'altered' ) ;
310+ }
311+ return cur ;
312+ } ) ;
313+ /* eslint-enable ts/ban-ts-comment */
314+
315+ expect ( generate ( alterRes , query ) ) . toEqual ( `<dust-in-the-wind> ,
292316 [ <right-now> "altered" ]
293317 ` ) ;
294318 } ) ;
0 commit comments