@@ -367,7 +367,14 @@ export function generateMissingIdsForBlankNodes(nquadsArray) {
367367 const updatedNquads = parser . parse ( nquadsArray . join ( "" ) ) . map ( ( quad ) => {
368368 // Check if BlankNodes are parsed as graphs
369369 if ( quad . graph . termType === "BlankNode" ) {
370- unsupportedNquads . push ( writer . quadToString ( quad . object , quad . predicate , quad . object , quad . graph ) ) ;
370+ unsupportedNquads . push (
371+ writer . quadToString (
372+ quad . object ,
373+ quad . predicate ,
374+ quad . object ,
375+ quad . graph
376+ )
377+ ) ;
371378 }
372379 // Replace blank nodes in the quad
373380 const updatedQuad = N3 . DataFactory . quad (
@@ -381,7 +388,7 @@ export function generateMissingIdsForBlankNodes(nquadsArray) {
381388 } ) ;
382389
383390 if ( unsupportedNquads . length > 0 ) {
384- throw new Error ( `
391+ throw new Error ( `
385392------------------------------------------------------------------------------------------------
386393Unsupported JSON-LD input detected
387394
@@ -392,9 +399,8 @@ Problematic Quads:
392399${ unsupportedNquads . map ( ( q , i ) => ` ${ i + 1 } . ${ q } ` ) . join ( "\n" ) }
393400
394401Full Parsed N-Quads Array:
395- ${ nquadsArray . join ( '\n' ) }
396- `
397- ) ;
402+ ${ nquadsArray . join ( "\n" ) }
403+ ` ) ;
398404 }
399405
400406 return writer . quadsToString ( updatedNquads ) . trimEnd ( ) . split ( "\n" ) ;
@@ -403,3 +409,65 @@ ${nquadsArray.join('\n')}
403409function isEmptyObject ( obj ) {
404410 return Object . keys ( obj ) . length === 0 && obj . constructor === Object ;
405411}
412+
413+ export function createKCTriples ( dataset , ual , publisher , merkleRoot ) {
414+ const kcId = ual . split ( "/" ) . pop ( ) ;
415+ const subjectTriplesMap = groupNquadsBySubject ( dataset . public ) ;
416+ const subjectTiplesSorted = subjectTriplesMap . sort ( ( a , b ) =>
417+ a . localeCompare ( b )
418+ ) ;
419+ const triples = [ ] ;
420+
421+ // Generate additional triples from dataset
422+ // Create reference triples -- once per KC
423+ // <did:dkg:.../KC_1> a dkg:KnowledgeCollection ;
424+ triples . push ( `<${ ual } > a dkg:KnowledgeCollection .` ) ;
425+ const kcRef = `<ref:${ ual } >` ;
426+ triples . push (
427+ `${ kcRef } a dkg:Reference ; dkg:collection <${ ual } > ; dkg:merkleRoot "${ merkleRoot } " ; prov:wasAttributedTo <${ publisher } > .`
428+ ) ;
429+ // <ref:UAL> a dkg:Reference ;
430+ // dkg:collection <did:dkg:.../KC_1> ;
431+ // dkg:merkleRoot "${merkleRoot}" ;
432+ // prov:wasAttributedTo <did:dkg:.../publisherX>
433+
434+ for ( const [ index , subjectTriples ] of subjectTiplesSorted . entries ( ) ) {
435+ // Bound KA ual to subject -- once per KA
436+ // <did:dkg:.../KC_1/KA_1> a dkg:KnowledgeAsset ;
437+ // dkg:assetOf <subject> .
438+ // TODO: Use library to extract subject from triple
439+ const subject = subjectTriples [ 0 ] . split ( " " ) [ 0 ] ;
440+ const kaId = `${ kcId } /${ index + 1 } ` ;
441+ const kaUAL = `${ ual } /${ kaId } ` ;
442+ const KASubjectRelation = `<${ kaUAL } > a dkg:KnowledgeAsset ; dkg:assetOf ${ subject } .` ;
443+ triples . push ( KASubjectRelation ) ;
444+ // Bound KA to KC -- once per KA
445+ // <did:dkg:.../KC_1> dkg:includesAsset <did:dkg:.../KC_1/KA_1> .
446+ const KAtoKCRelation = `<${ ual } > dkg:includesAsset <${ kaUAL } > .` ;
447+ triples . push ( KASubjectRelation , KAtoKCRelation ) ;
448+ // For each triple:
449+ // Generate statement triples -- for each KA statment
450+ for ( const triple of subjectTriples ) {
451+ const [ predicate , object ] = triple . split ( " " ) . slice ( 1 ) ;
452+ const spoHash = ethers . utils . keccak256 (
453+ `${ subject } ||${ predicate } ||${ object } `
454+ ) ;
455+ const statementTriple = `<stmt:${ kcId } :${ kaId } :${ spoHash } > a dkg:Statement ;
456+ dkg:aboutSubject ${ subject } ;
457+ dkg:forPredicate ${ predicate } ;
458+ dkg:hasValue ${ object } ;
459+ dkg:rank dkg:PreferredRank ;
460+ prov:wasAttributedTo <${ publisher } > ;
461+ prov:wasDerivedFrom <${ ual } /${ kcId } > .` ;
462+ triples . push ( statementTriple ) ;
463+ // <stmt:KC_1:KA_1:<hash-s-p-o> a dkg:Statement ;
464+ // dkg:aboutSubject <subject> ;
465+ // dkg:forPredicate <predicate> ;
466+ // dkg:hasValue <object> ;
467+ // dkg:rank dkg:PreferredRank ;
468+ // prov:wasAttributedTo <did:dkg:.../publisher> ;
469+ // prov:wasDerivedFrom <ref:KC_1> ;
470+ // prov:generatedAtTime "2025-09-03T10:00:00Z"^^xsd:dateTime .
471+ }
472+ }
473+ }
0 commit comments