1- import { OutlineTree , Outline , RawOutline } from "./lib/outline" ;
2- import { ContentNode , IContentNode } from "./lib/contentNode" ;
1+ import { Outline , RawOutline } from "./lib/outline" ;
32import { slugify } from './lib/string' ;
43import * as _ from 'lodash' ;
54import * as fs from '@tauri-apps/plugin-fs' ;
6-
7- type RawOutlineData = {
8- id : string ;
9- name : string ;
10- created : number ;
11- lastModified : number ;
12- }
13-
14- type OutlineDataStorage = {
15- id : string ;
16- version : string ;
17- created : number ;
18- name : string ;
19- tree : OutlineTree ;
20- }
5+ import { parseOpmlToRawOutline , serializeRawOutlineToOpml } from './lib/opml' ;
216
227export class ApiClient {
238 dir = fs . BaseDirectory . AppLocalData ;
@@ -27,10 +12,10 @@ export class ApiClient {
2712 }
2813
2914 async createDirStructureIfNotExists ( ) {
30- if ( ! await fs . exists ( 'outliner/contentNodes ' , {
15+ if ( ! await fs . exists ( 'outliner' , {
3116 baseDir : fs . BaseDirectory . AppLocalData
3217 } ) ) {
33- await fs . mkdir ( 'outliner/contentNodes ' , {
18+ await fs . mkdir ( 'outliner' , {
3419 baseDir : fs . BaseDirectory . AppLocalData ,
3520 recursive : true
3621 } ) ;
@@ -43,76 +28,41 @@ export class ApiClient {
4328 } ) ;
4429
4530 return files . filter ( obj => {
46- return ! obj . isDirectory
31+ return ! obj . isDirectory && obj . name ?. toLowerCase ( ) . endsWith ( '.opml' ) ;
4732 } ) ;
4833 }
4934
50- async loadOutline ( outlineName : string ) : Promise < RawOutline > {
51- const raw = await fs . readTextFile ( `outliner/${ slugify ( outlineName ) } .json` , {
35+ private normalizeOutlineFilename ( nameOrFilename : string ) : string {
36+ const trimmed = nameOrFilename . trim ( ) ;
37+ if ( trimmed . toLowerCase ( ) . endsWith ( '.opml' ) ) {
38+ return trimmed ;
39+ }
40+ return `${ slugify ( trimmed ) } .opml` ;
41+ }
42+
43+ async loadOutline ( outlineNameOrFilename : string ) : Promise < RawOutline > {
44+ const filename = this . normalizeOutlineFilename ( outlineNameOrFilename ) ;
45+ const raw = await fs . readTextFile ( `outliner/${ filename } ` , {
5246 baseDir : fs . BaseDirectory . AppLocalData
5347 } ) ;
54-
55- const rawOutline = JSON . parse ( raw ) as OutlineDataStorage ;
56-
57- const contentNodeIds = _ . uniq ( JSON . stringify ( rawOutline . tree ) . match ( / [ 0 - 9 a - f ] { 8 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 12 } / gi) ) ;
58-
59- // the first node is always the root
60- contentNodeIds . shift ( ) ;
61-
62- const rawContentNodes = await Promise . allSettled ( _ . map ( contentNodeIds , ( id ) => {
63- return fs . readTextFile ( `outliner/contentNodes/${ id } .json` , {
64- baseDir : fs . BaseDirectory . AppLocalData
65- } )
66- } ) ) ;
67-
68- return {
69- id : rawOutline . id ,
70- version : rawOutline . version ,
71- created : rawOutline . created ,
72- name : rawOutline . name ,
73- tree : rawOutline . tree ,
74- contentNodes : _ . keyBy ( _ . map ( rawContentNodes , raw => {
75- if ( raw . status === 'fulfilled' ) {
76- return ContentNode . Create ( JSON . parse ( raw . value ) as IContentNode )
77- }
78- else {
79- console . log ( 'rejected node' , raw . reason ) ;
80- }
81- } ) , n => n . id )
82- }
48+ return parseOpmlToRawOutline ( raw ) ;
8349 }
8450
8551 async saveOutline ( outline : Outline ) {
86- await fs . writeTextFile ( `outliner/${ slugify ( outline . data . name ) } .json` , JSON . stringify ( {
87- id : outline . data . id ,
88- version : outline . data . version ,
89- created : outline . data . created ,
90- name : outline . data . name ,
91- tree : outline . data . tree
92- } ) , {
52+ await fs . writeTextFile ( `outliner/${ slugify ( outline . data . name ) } .opml` , serializeRawOutlineToOpml ( outline . data ) , {
9353 baseDir : fs . BaseDirectory . AppLocalData ,
9454 } ) ;
9555 }
9656
9757 async renameOutline ( oldName : string , newName : string ) {
9858 if ( newName . length && oldName !== newName ) {
99- return fs . rename ( `outliner/${ slugify ( oldName ) } .json ` , `outliner/${ slugify ( newName ) } .json ` , {
59+ return fs . rename ( `outliner/${ slugify ( oldName ) } .opml ` , `outliner/${ slugify ( newName ) } .opml ` , {
10060 oldPathBaseDir : fs . BaseDirectory . AppLocalData ,
10161 newPathBaseDir : fs . BaseDirectory . AppLocalData ,
10262 } ) ;
10363 }
10464 }
10565
106- async saveContentNode ( node : ContentNode ) {
107- try {
108- await fs . writeTextFile ( `outliner/contentNodes/${ node . id } .json` , JSON . stringify ( node . toJson ( ) ) , {
109- baseDir : fs . BaseDirectory . AppLocalData
110- } ) ;
111- } catch ( e ) {
112- console . error ( e ) ;
113- }
114- }
115-
11666 save ( outline : Outline ) {
11767 if ( ! this . state . has ( 'saveTimeout' ) ) {
11868 this . state . set ( 'saveTimeout' , setTimeout ( async ( ) => {
0 commit comments