@@ -24,18 +24,20 @@ const MarkdownItRuby = require('markdown-it-ruby')
2424const htmlEncode = require ( 'htmlencode' ) . htmlEncode ;
2525
2626export class Convert {
27- src : Array < string >
28- dest : string
29- layout : string
30- md : MarkdownIt
31- metadata : Metadata
27+ private md : MarkdownIt
28+ private metadata : Metadata
29+ private layout : string
3230
33- constructor ( src : Array < string > , dest : string , layout : string , hardBreak : boolean ) {
34- this . src = src
35- this . dest = dest
36- this . layout = layout
31+ /**
32+ * @param layout set null if you want to use default layout,
33+ * @param hardBreak set true if want to use hardBread
34+ */
35+ constructor ( layout : string | null , hardBreak : boolean = false ) {
3736 this . metadata = new Metadata ( )
38-
37+ if ( layout === null ) {
38+ layout = this . defaultLayout ( )
39+ }
40+ this . layout = layout
3941 // https://hackmd.io/c/codimd-documentation/%2F%40codimd%2Fmarkdown-syntax
4042 this . md = new MarkdownIt ( {
4143 html : true ,
@@ -69,86 +71,117 @@ export class Convert {
6971 . use ( MarkdownItFenceX )
7072 }
7173
72- // @param html: html string
73- // @return : html string with layout
74- private addLayout ( metadata : Metadata , html : string ) : string {
75- if ( fs . existsSync ( this . layout ) ) {
76- const layout = fs . readFileSync ( this . layout , { encoding : 'utf-8' } )
77- let metas = ''
78- if ( metadata . title !== '' ) {
79- metas += '<title>' + htmlEncode ( metadata . title ) + '</title>\n'
80- metas += '<meta name="twitter:title" content="' + htmlEncode ( metadata . title ) + '" />\n'
81- metas += '<meta property="og:title" content="' + htmlEncode ( metadata . title ) + '" />\n'
82- }
83- if ( metadata . robots !== '' ) {
84- metas += '<meta name="robots" content="' + htmlEncode ( metadata . robots ) + '">\n'
85- }
86- if ( metadata . description !== '' ) {
87- metas += '<meta name="description" content="' + htmlEncode ( metadata . description ) + '">\n'
88- metas += '<meta name="twitter:description" content="' + htmlEncode ( metadata . description ) + '">\n'
89- metas += '<meta property="og:description" content="' + htmlEncode ( metadata . description ) + '">\n'
90- }
91- if ( metadata . image !== '' ) {
92- metas += '<meta name="twitter:image:src" content="' + htmlEncode ( metadata . image ) + '" />\n'
93- metas += '<meta property="og:image" content="' + htmlEncode ( metadata . image ) + '" />\n'
94- }
95- let lang = ''
96- if ( metadata . lang !== '' ) {
97- lang = ' lang="' + htmlEncode ( metadata . lang ) + '"'
98- }
99- let dir = ''
100- if ( metadata . dir !== '' ) {
101- dir = ' dir="' + htmlEncode ( metadata . dir ) + '"'
102- }
103- return layout
104- . replace ( '{{lang}}' , lang )
105- . replace ( '{{dir}}' , dir )
106- . replace ( '{{metas}}' , metas )
107- . replace ( '{{main}}' , html )
74+ /**
75+ * @param main main HTML string converted by MarkdownIt
76+ * @returns generated code
77+ */
78+ private useLayout ( main : string ) : string {
79+ const metadata = this . metadata
80+ let metas = ''
81+ if ( metadata . title !== '' ) {
82+ metas += '<title>' + htmlEncode ( metadata . title ) + '</title>\n'
83+ metas += '<meta name="twitter:title" content="' + htmlEncode ( metadata . title ) + '" />\n'
84+ metas += '<meta property="og:title" content="' + htmlEncode ( metadata . title ) + '" />\n'
85+ }
86+ if ( metadata . robots !== '' ) {
87+ metas += '<meta name="robots" content="' + htmlEncode ( metadata . robots ) + '">\n'
88+ }
89+ if ( metadata . description !== '' ) {
90+ metas += '<meta name="description" content="' + htmlEncode ( metadata . description ) + '">\n'
91+ metas += '<meta name="twitter:description" content="' + htmlEncode ( metadata . description ) + '">\n'
92+ metas += '<meta property="og:description" content="' + htmlEncode ( metadata . description ) + '">\n'
93+ }
94+ if ( metadata . image !== '' ) {
95+ metas += '<meta name="twitter:image:src" content="' + htmlEncode ( metadata . image ) + '" />\n'
96+ metas += '<meta property="og:image" content="' + htmlEncode ( metadata . image ) + '" />\n'
97+ }
98+ let lang = ''
99+ if ( metadata . lang !== '' ) {
100+ lang = ' lang="' + htmlEncode ( metadata . lang ) + '"'
101+ }
102+ let dir = ''
103+ if ( metadata . dir !== '' ) {
104+ dir = ' dir="' + htmlEncode ( metadata . dir ) + '"'
108105 }
109106
110- console . error ( `${ this . layout } is not found` )
111- return html
107+ return `${ this . layout } `
108+ . replace ( '{{lang}}' , lang )
109+ . replace ( '{{dir}}' , dir )
110+ . replace ( '{{metas}}' , metas )
111+ . replace ( '{{main}}' , main )
112112 }
113113
114- // @param filepath: the path of the file should be converted
115- // this function doesn't check the ext name of filepath
116- public convertFile ( filepath : string ) {
117- const markdown = fs . readFileSync ( filepath , { encoding : 'utf-8' } )
114+ /**
115+ * @param markdown markdown text
116+ * @returns generated html text
117+ */
118+ public convert ( markdown : string ) : string {
118119 const html = this . md . render ( markdown )
119- const res = this . addLayout ( this . metadata , html )
120- const basename = path . basename ( filepath )
121- fs . writeFileSync ( path . join ( this . dest , basename . replace ( / \. m d $ / , '.html' ) ) , res )
120+ return this . useLayout ( html )
121+ }
122+
123+ /**
124+ * Get metadata after converting.
125+ * Before calling this function, Please call convert() first
126+ * @returns metadata of the markdown file
127+ */
128+ public getMetadata ( ) : Metadata {
129+ return this . metadata
130+ }
131+
132+ /**
133+ * @returns default HTML layout
134+ */
135+ public defaultLayout ( ) : string {
136+ return fs . readFileSync ( path . join ( __dirname , '../layout.html' ) , { encoding : 'utf-8' } )
122137 }
123138
124- public convertBatch ( ) {
125- if ( ! fs . existsSync ( this . dest ) ) {
126- fs . mkdirSync ( this . dest )
139+ /**
140+ * ```
141+ *
142+ * .
143+ * ├── foo
144+ * │ ├── a.md
145+ * │ └── b.md
146+ * ├── c.md
147+ * └── out
148+ * ├── foo
149+ * │ ├── a.html
150+ * │ └── b.html
151+ * └── c.html
152+ * ```
153+ * @param filePathsOrDir a list of the path of files or directories e.g. ["./foo", "c.md"]
154+ * @param destDir the path of destination directory e.g. ["./build"]
155+ */
156+ public convertFiles ( filePathsOrDir : fs . PathLike [ ] , destDir : fs . PathLike ) {
157+ console . log ( filePathsOrDir )
158+
159+ if ( ! fs . existsSync ( destDir ) ) {
160+ fs . mkdirSync ( destDir )
127161 }
128- this . src . forEach ( ( fileOrDir : string ) => {
129- if ( ! fs . existsSync ( fileOrDir ) ) {
130- console . error ( `${ fileOrDir } is not found` )
162+
163+ const files : fs . PathLike [ ] = [ ]
164+ filePathsOrDir . forEach ( ( fn : fs . PathLike ) => {
165+ if ( ! fs . existsSync ( fn ) ) {
166+ console . error ( `${ fn } is not found` )
131167 return
132168 }
133-
134- const stats = fs . statSync ( fileOrDir )
135-
169+ const stats = fs . statSync ( fn )
136170 if ( stats . isDirectory ( ) ) {
137- fs . readdir ( fileOrDir , ( err : NodeJS . ErrnoException | null , files : string [ ] ) => {
138- if ( err ) {
139- throw ( err )
140- }
141- files ?. forEach ( ( fn ) => {
142- if ( path . extname ( fn ) === '.md' ) {
143- this . convertFile ( path . join ( fileOrDir , fn ) )
144- }
145- } )
171+ const f = fs . readdirSync ( fn )
172+ f . forEach ( ( e : fs . PathLike ) => {
173+ files . push ( path . join ( fn . toString ( ) , e . toString ( ) ) )
146174 } )
147175 } else if ( stats . isFile ( ) ) {
148- if ( path . extname ( fileOrDir ) === '.md' ) {
149- this . convertFile ( fileOrDir )
150- }
176+ files . push ( fn )
151177 }
152178 } )
179+
180+ files . forEach ( ( fn : fs . PathLike ) => {
181+ const markdown = fs . readFileSync ( fn , { encoding : 'utf-8' } )
182+ const res = this . convert ( markdown )
183+ const basename = path . basename ( fn . toString ( ) )
184+ fs . writeFileSync ( path . join ( destDir . toString ( ) , basename . replace ( / \. m d $ / , '.html' ) ) , res )
185+ } ) ;
153186 }
154- }
187+ }
0 commit comments