7575 *
7676 * @param {object } gx - the a GEDOMX dataset parsed from JSON format
7777 * @param {function } error - a vararg function accepting error messages; for example, `console.error`
78+ * @param {string } format - `text/json` if want prototype g7 JSON; otherwise get GEDCOM string
7879 * @returns {string } a corresponding GEDCOM 7.0 dataset
7980 */
80- function GEDCOMXTo7 ( gx , error ) {
81+ function GEDCOMXTo7 ( gx , error , format ) {
8182
8283 if ( ! error ) error = ( ...args ) => { }
8384 const xlinks = { }
@@ -96,11 +97,13 @@ function GEDCOMXTo7(gx, error) {
9697 this . tag = tag
9798 this . id = null
9899 this . payload = payload
99- if ( payload && 'object' == typeof payload ) {
100+ if ( payload === null ) {
101+ this . payload = null
102+ } else if ( payload && 'object' == typeof payload ) {
100103 this . payload = payload
101104 if ( ! payload . id ) this . payload . id = 'X' + ( g7s . nextXrefID += 1 )
102105 } else if ( payload ) this . payload = String ( payload ) . replace ( / \r \n ? / g, '\n' )
103- else this . payload = null
106+ else this . payload = undefined
104107 this . subs = substructures . filter ( x => x )
105108 }
106109 g7s . nextXrefID = 0
@@ -109,7 +112,7 @@ function GEDCOMXTo7(gx, error) {
109112 let self = level + ( this . id ? ' @' + this . id + '@' :'' ) + ' ' + this . tag
110113 if ( this . payload && 'object' == typeof this . payload ) {
111114 self += ' @' + this . payload . id + '@'
112- } else if ( this . payload == '@VOID@' ) {
115+ } else if ( this . payload === null ) {
113116 self += ' @VOID@'
114117 } else if ( this . payload ) {
115118 let txt = this . payload . replace ( / \n ( @ ? ) / g, `\n${ level + 1 } CONT $1$1` ) . replace ( / ^ ( [ 0 - 9 ] + C O N T ) $ / mg, "$1" )
@@ -119,6 +122,15 @@ function GEDCOMXTo7(gx, error) {
119122 }
120123 return self + '\n' + this . subs . map ( s => s . toString ( level + 1 ) ) . join ( '' )
121124 }
125+ g7s . prototype . toJSO = function ( ) {
126+ const ans = { 'tag' :this . tag }
127+ if ( this . id ) ans . id = this . id
128+ if ( this . payload === null ) ans . pointer = null
129+ else if ( 'object' == typeof this . payload ) ans . pointer = '#' + this . payload . id
130+ else if ( 'string' == typeof this . payload ) ans . text = this . payload
131+ if ( this . subs . length > 0 ) ans . subs = this . subs . map ( x => x . toJSO ( ) )
132+ return ans
133+ }
122134 g7s . prototype . add = function ( ...subs ) { this . subs . push ( ...subs . filter ( x => x ) ) }
123135
124136 const parseDataURL = uri => {
@@ -131,7 +143,7 @@ function GEDCOMXTo7(gx, error) {
131143
132144
133145 let records = { }
134- let header = g7s ( 'HEAD' , null , g7s ( 'GEDC' , null , g7s ( 'VERS' , '7.0' ) ) )
146+ let header = g7s ( 'HEAD' , undefined , g7s ( 'GEDC' , undefined , g7s ( 'VERS' , '7.0' ) ) )
135147 let extensions = [ ]
136148 let trailer = g7s ( 'TRLR' )
137149
@@ -167,12 +179,12 @@ function GEDCOMXTo7(gx, error) {
167179 return ans
168180 }
169181 if ( 'original' in d ) {
170- return g7s ( 'DATE' , null , g7s ( 'PHRASE' , d . original ) )
182+ return g7s ( 'DATE' , undefined , g7s ( 'PHRASE' , d . original ) )
171183 } else return null
172184 }
173185 let bits = d . split ( '/' )
174186 let phrases = [ ]
175- if ( bits . length > 3 ) return g7s ( 'DATE' , null , g7s ( 'PHRASE' , 'unsupported gedcomx data: ' + d ) )
187+ if ( bits . length > 3 ) return g7s ( 'DATE' , undefined , g7s ( 'PHRASE' , 'unsupported gedcomx data: ' + d ) )
176188 if ( bits . length == 3 ) {
177189 // recurring
178190 let times = bits [ 0 ] . substr ( 1 )
@@ -281,12 +293,12 @@ function GEDCOMXTo7(gx, error) {
281293 }
282294 if ( kml ) {
283295 if ( ! ( kml in records ) ) {
284- records [ kml ] = g7s ( 'OBJE' , null , g7s ( 'FILE' , kml , g7s ( 'MEDI' , 'application/vnd.google-earth.kml+xml' ) ) )
296+ records [ kml ] = g7s ( 'OBJE' , undefined , g7s ( 'FILE' , kml , g7s ( 'MEDI' , 'application/vnd.google-earth.kml+xml' ) ) )
285297 }
286298 ans . add ( g7s ( '_OBJE' , records [ kml ] ) )
287299 }
288300 if ( map ) {
289- ans . add ( g7s ( 'MAP' , null ,
301+ ans . add ( g7s ( 'MAP' , undefined ,
290302 g7s ( 'LATI' , ( map . latitude < 0 ?'S' :'N' ) + Math . abs ( map . latitude ) ) ,
291303 g7s ( 'LONG' , ( map . longitude < 0 ?'W' :'E' ) + Math . abs ( map . longitude ) ) ,
292304 ) )
@@ -382,7 +394,7 @@ function GEDCOMXTo7(gx, error) {
382394
383395 /** INDI records */
384396 const doPerson = p => {
385- let me = records [ '#' + p . id ] || g7s ( 'INDI' , null , g7s ( 'EXID' , p . id , g7s ( 'TYPE' , 'https://gedcom.io/exid-type/FamilySearch-PersonId' ) ) )
397+ let me = records [ '#' + p . id ] || g7s ( 'INDI' , undefined , g7s ( 'EXID' , p . id , g7s ( 'TYPE' , 'https://gedcom.io/exid-type/FamilySearch-PersonId' ) ) )
386398 let modified = 0
387399 let didLiving = false
388400
@@ -431,7 +443,7 @@ function GEDCOMXTo7(gx, error) {
431443 if ( p . living === false ) me . add ( g7s ( 'DEAT' , 'Y' ) )
432444 else if ( p . living ) me . add ( g7s ( 'NO' , 'DEAT' ) )
433445 }
434- if ( modified ) me . add ( g7s ( 'CHAN' , null , doDate ( modified ) ) )
446+ if ( modified ) me . add ( g7s ( 'CHAN' , undefined , doDate ( modified ) ) )
435447 records [ '#' + p . id ] = me
436448 me . resourceId = p . id // not displayed, just for local interlinks
437449 }
@@ -440,7 +452,7 @@ function GEDCOMXTo7(gx, error) {
440452 const makeOrFindFam = ( p1 , p2 ) => {
441453 let id = [ p1 ?. resourceId , p2 ?. resourceId ] . sort ( ) . join ( '+' )
442454 if ( id in records ) return records [ id ]
443- let ans = g7s ( 'FAM' , null ,
455+ let ans = g7s ( 'FAM' , undefined ,
444456 p1 ?g7s ( 'HUSB' , records [ '#' + p1 . resourceId ] ) :null ,
445457 p2 ?g7s ( 'WIFE' , records [ '#' + p2 . resourceId ] ) :null ,
446458 )
@@ -548,7 +560,7 @@ function GEDCOMXTo7(gx, error) {
548560 ans = g7s ( atags [ f . type ] , f . value )
549561 if ( ans . tag == 'IDNO' ) ans . add ( g7s ( 'TYPE' , 'Unspecified' ) ) // fix me: figure out why no NationalId fields have nations in FS data I've seen
550562 } else if ( f . type in evens ) {
551- ans = g7s ( 'EVEN' , null , g7s ( 'TYPE' , evens [ f . type ] ) )
563+ ans = g7s ( 'EVEN' , undefined , g7s ( 'TYPE' , evens [ f . type ] ) )
552564 if ( f . value ) ans . add ( g7s ( 'NOTE' , f . value ) )
553565 } else if ( f . type in facts ) {
554566 ans = g7s ( 'FACT' , f . value , g7s ( 'TYPE' , facts [ f . type ] ) )
@@ -607,7 +619,7 @@ function GEDCOMXTo7(gx, error) {
607619 } else if ( f . type in atags ) {
608620 ans = g7s ( atags [ f . type ] , f . value )
609621 } else if ( f . type in evens ) {
610- ans = g7s ( 'EVEN' , null , g7s ( 'TYPE' , evens [ f . type ] ) )
622+ ans = g7s ( 'EVEN' , undefined , g7s ( 'TYPE' , evens [ f . type ] ) )
611623 if ( f . value ) ans . add ( g7s ( 'NOTE' , f . value ) )
612624 } else if ( f . type in facts ) {
613625 ans = g7s ( 'FACT' , f . value , g7s ( 'TYPE' , facts [ f . type ] ) )
@@ -638,9 +650,9 @@ function GEDCOMXTo7(gx, error) {
638650 const doRelationship1 = r => {
639651 if ( r . type != 'http://gedcomx.org/Couple' ) return
640652 if ( ! ( '#' + r . person1 . resourceId in records ) )
641- records [ '#' + r . person1 . resourceId ] = g7s ( 'INDI' , null , g7s ( 'EXID' , r . person1 . resourceId , g7s ( 'TYPE' , 'https://gedcom.io/exid-type/FamilySearch-PersonId' ) ) )
653+ records [ '#' + r . person1 . resourceId ] = g7s ( 'INDI' , undefined , g7s ( 'EXID' , r . person1 . resourceId , g7s ( 'TYPE' , 'https://gedcom.io/exid-type/FamilySearch-PersonId' ) ) )
642654 if ( ! ( '#' + r . person2 . resourceId in records ) )
643- records [ '#' + r . person2 . resourceId ] = g7s ( 'INDI' , null , g7s ( 'EXID' , r . person2 . resourceId , g7s ( 'TYPE' , 'https://gedcom.io/exid-type/FamilySearch-PersonId' ) ) )
655+ records [ '#' + r . person2 . resourceId ] = g7s ( 'INDI' , undefined , g7s ( 'EXID' , r . person2 . resourceId , g7s ( 'TYPE' , 'https://gedcom.io/exid-type/FamilySearch-PersonId' ) ) )
644656 let id = [ r . person1 . resourceId , r . person2 . resourceId ] . sort ( ) . join ( '+' )
645657 let fam = makeOrFindFam ( r . person1 , r . person2 )
646658 fam . add ( g7s ( 'EXID' , r . id , g7s ( 'TYPE' , 'https://gedcom.io/exid-type/FamilySearch-RelationshipId' ) ) ) // FIX ME: register this type
@@ -692,13 +704,13 @@ function GEDCOMXTo7(gx, error) {
692704 for ( let i = 0 ; i < fam . subs . length ; i += 1 ) if ( fam . subs [ i ] . tag == 'CHIL' ) {
693705 chilnum -= 1
694706 if ( chilnum == 0 ) {
695- if ( fam . subs [ i ] . payload == '@VOID@' ) fam . subs [ i ] . payload = per
707+ if ( fam . subs [ i ] . payload === null ) fam . subs [ i ] . payload = per
696708 else fam . subs . splice ( i , 0 , g7s ( 'CHIL' , per ) )
697709 break
698710 }
699711 }
700712 if ( chilnum > 0 ) {
701- while ( chilnum > 1 ) { fam . add ( g7s ( 'CHIL' , '@VOID@' ) ) ; chilnum -= 1 ; }
713+ while ( chilnum > 1 ) { fam . add ( g7s ( 'CHIL' , null ) ) ; chilnum -= 1 ; }
702714 fam . add ( g7s ( 'CHIL' , per ) )
703715 }
704716 }
@@ -739,6 +751,7 @@ function GEDCOMXTo7(gx, error) {
739751
740752
741753
742- if ( extensions ) header . add ( g7s ( 'SCHMA' , null , ...extensions ) )
754+ if ( extensions . length > 0 ) header . add ( g7s ( 'SCHMA' , undefined , ...extensions ) )
755+ if ( format == 'text/json' ) return [ header . toJSO ( ) ] . concat ( Object . values ( records ) . map ( x => x . toJSO ( ) ) )
743756 return header + Object . values ( records ) . join ( '' ) + trailer
744757}
0 commit comments