@@ -38,6 +38,31 @@ type getExportTypesProps = {
3838 isExportDiscourseGraph : boolean ;
3939} ;
4040
41+ /* eslint-disable @typescript-eslint/naming-convention */
42+ type RoamImportUser = {
43+ ":user/uid" : string ;
44+ } ;
45+
46+ type RoamImportBlock = {
47+ string : string ;
48+ uid ?: string ;
49+ children ?: RoamImportBlock [ ] ;
50+ "create-time" ?: number ;
51+ "edit-time" ?: number ;
52+ "edit-user" ?: RoamImportUser ;
53+ heading ?: 0 | 1 | 2 | 3 ;
54+ "text-align" ?: "left" | "center" | "right" | "justify" ;
55+ } ;
56+
57+ type RoamImportPage = {
58+ title : string ;
59+ children ?: RoamImportBlock [ ] ;
60+ "create-time" ?: number ;
61+ "edit-time" ?: number ;
62+ "edit-user" ?: RoamImportUser ;
63+ } ;
64+ /* eslint-enable @typescript-eslint/naming-convention */
65+
4166const getExportTypes = ( {
4267 results,
4368 exportId,
@@ -53,6 +78,49 @@ const getExportTypes = ({
5378 const getRelationData = ( ) =>
5479 getRelationDataUtil ( { allRelations, nodeLabelByType, local : true } ) ;
5580
81+ const getRoamImportUser = ( ) : RoamImportUser | undefined => {
82+ const userUid = window . roamAlphaAPI . user . uid ( ) ;
83+ if ( ! userUid ) return undefined ;
84+ const user = { } as RoamImportUser ;
85+ user [ ":user/uid" ] = userUid ;
86+ return user ;
87+ } ;
88+
89+ const toEpochMilliseconds = ( value : Date ) : number | undefined => {
90+ const time = value . getTime ( ) ;
91+ return Number . isFinite ( time ) && time > 0 ? time : undefined ;
92+ } ;
93+
94+ const toRoamHeading = ( heading : number ) : 0 | 1 | 2 | 3 => {
95+ if ( heading === 1 || heading === 2 || heading === 3 ) return heading ;
96+ return 0 ;
97+ } ;
98+
99+ const toRoamImportBlock = (
100+ node : TreeNode ,
101+ editUser : RoamImportUser | undefined ,
102+ ) : RoamImportBlock => {
103+ const editTime = toEpochMilliseconds ( node . editTime ) ;
104+ const heading = toRoamHeading ( node . heading ) ;
105+ const children = node . children . map ( ( child ) =>
106+ toRoamImportBlock ( child , editUser ) ,
107+ ) ;
108+
109+ const block : RoamImportBlock = {
110+ string : node . text ,
111+ uid : node . uid || undefined ,
112+ children : children . length ? children : undefined ,
113+ heading,
114+ } ;
115+ block [ "create-time" ] = editTime ;
116+ block [ "edit-time" ] = editTime ;
117+ block [ "edit-user" ] = editUser ;
118+ if ( node . textAlign && node . textAlign !== "left" ) {
119+ block [ "text-align" ] = node . textAlign ;
120+ }
121+ return block ;
122+ } ;
123+
56124 const getJsonData = async ( results : Result [ ] ) => {
57125 const grammar = allRelations . map ( ( { label, destination, source } ) => ( {
58126 label,
@@ -79,6 +147,27 @@ const getExportTypes = ({
79147 } ) ;
80148 } ;
81149
150+ const getRoamImportData = ( results : Result [ ] ) : RoamImportPage [ ] => {
151+ const editUser = getRoamImportUser ( ) ;
152+ return getPageData ( { results, allNodes, isExportDiscourseGraph } ) . map (
153+ ( { text, uid } ) => {
154+ const { children } = getFullTreeByParentUid ( uid ) ;
155+ const { date, modified } = getPageMetadata ( text ) ;
156+ const createTime = toEpochMilliseconds ( date ) ;
157+ const editTime = toEpochMilliseconds ( modified ) ;
158+
159+ const page : RoamImportPage = {
160+ title : text ,
161+ children : children . map ( ( node ) => toRoamImportBlock ( node , editUser ) ) ,
162+ } ;
163+ page [ "create-time" ] = createTime ;
164+ page [ "edit-time" ] = editTime || createTime ;
165+ page [ "edit-user" ] = editUser ;
166+ return page ;
167+ } ,
168+ ) ;
169+ } ;
170+
82171 return [
83172 {
84173 name : "Markdown" ,
@@ -145,6 +234,19 @@ const getExportTypes = ({
145234 ] ;
146235 } ,
147236 } ,
237+ {
238+ name : "Roam Import JSON" ,
239+ callback : ( { filename } ) => {
240+ if ( ! results ) return Promise . resolve ( [ ] ) ;
241+ const data = getRoamImportData ( results ) ;
242+ return Promise . resolve ( [
243+ {
244+ title : `${ filename . replace ( / \. j s o n $ / , "" ) } .json` ,
245+ content : JSON . stringify ( data , undefined , 2 ) ,
246+ } ,
247+ ] ) ;
248+ } ,
249+ } ,
148250 {
149251 name : "JSON-LD (Experimental)" ,
150252 callback : async ( { filename } ) => {
0 commit comments