Skip to content

Commit afd2ab0

Browse files
committed
Allow the package to be imported
1 parent 1d76701 commit afd2ab0

File tree

6 files changed

+123
-85
lines changed

6 files changed

+123
-85
lines changed

lib/container.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import StateBlock from "markdown-it/lib/rules_block/state_block"
55
import Token from "markdown-it/lib/token"
66

77
const names = ['success', 'info', 'warning', 'danger', 'spoiler']
8-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
8+
99
export function MarkdownItContainer(md: MarkdownIt, _options: MarkdownIt.Options) {
1010
// Second param may be useful if you decide
1111
// to increase minimal allowed marker length

lib/converter.ts

Lines changed: 110 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,20 @@ const MarkdownItRuby = require('markdown-it-ruby')
2424
const htmlEncode = require('htmlencode').htmlEncode;
2525

2626
export 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(/\.md$/, '.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(/\.md$/, '.html')), res)
185+
});
153186
}
154-
}
187+
}

lib/index.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22
import commander from 'commander'
3-
import path from 'path'
3+
import fs from 'fs'
44
import { Convert } from './converter'
55

66
commander.program.version('0.0.10', '-v, --version', 'output the current version')
@@ -14,6 +14,9 @@ commander.program
1414
const options = commander.program.opts()
1515

1616
const dest: string = options.destination === '' ? './output' : options.destination
17-
const layout: string = options.layout === '' ? path.join(__dirname, '../layout.html') : options.layout
17+
const layout: string | null = options.layout !== '' ? fs.readFileSync(options.layout, { encoding: 'utf-8' }) : null
1818
const hardBreak: boolean = options.hardBreak
19-
new Convert(options.source, dest, layout, hardBreak).convertBatch()
19+
20+
const converter = new Convert(layout, hardBreak)
21+
22+
converter.convertFiles(options.source, dest)

lib/yaml-metadata.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export function MarkdownItYAMLMetadata(md: MarkdownIt, callback: (metadata: Meta
6060
return true
6161
}
6262

63+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
6364
function renderer(tokens: Token[], idx: number, _options: MarkdownIt.Options, _evn: any): string {
6465
const token = tokens[idx]!
6566
if (callback) {

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"bin": {
1818
"hmd2html": "dist/index.js"
1919
},
20-
"types": "types/index.d.ts",
20+
"main":"dist/converter.js",
21+
"types": "types/converter.d.ts",
2122
"scripts": {
2223
"build": "tsc",
2324
"test": "tsc & npx hmd2html -s ./example",

tsconfig.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,18 @@
4242
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
4343

4444
/* Emit */
45-
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
45+
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
4646
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
4747
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
4848
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
4949
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
50-
"outDir": "dist", /* Specify an output folder for all emitted files. */
50+
"outDir": "./dist", /* Specify an output folder for all emitted files. */
5151
"removeComments": false, /* Disable emitting comments. */
5252
// "noEmit": true, /* Disable emitting files from a compilation. */
5353
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
5454
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
5555
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
56-
"sourceRoot": "./src", /* Specify the root path for debuggers to find the reference source code. */
56+
"sourceRoot": "./lib", /* Specify the root path for debuggers to find the reference source code. */
5757
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
5858
"inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
5959
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */

0 commit comments

Comments
 (0)