Skip to content

Instantly share code, notes, and snippets.

@AnonymerNiklasistanonym
Last active February 28, 2019 05:00
Show Gist options
  • Save AnonymerNiklasistanonym/7b32fa0a9f19f50f401cdf3685f54289 to your computer and use it in GitHub Desktop.
Save AnonymerNiklasistanonym/7b32fa0a9f19f50f401cdf3685f54289 to your computer and use it in GitHub Desktop.
Convert a markdown note written in Notable (https://github.com/notable/notable) to a markdown document readable by another Markdown editor like Typora (https://typora.io/) via a CLI node script
const fs = require('fs')
const path = require('path')
const colors = require('colors')
/**
* Info option, when true enable performance tracking and other infos
*/
let enableInfo = false
/**
* String that replaces `@attachment` in `img` tags
*/
let replaceWith = 'attachments'
/**
* CLI Help output
*/
const helpOutput = () => {
console.log('Description:\n' +
'\tScraps Markdown note created with Notable for used resources to\n' +
'\tedit it and export it to a new file that can be edited in Typora.')
console.log('Example:\n\t$ node ' +
colors.yellow('.\\notableNoteToTypora.js ') +
colors.green('filePath.md ') +
colors.red('-enableOptionalOption') +
'\n\tFile was written: "filePath_typora.md"')
console.log('Options:\n' + '\t-info\t\t\t\t' +
colors.grey('Get information about performance\n\t\t\t\t\tand other things') +
'\n\t-customReplace ' + colors.magenta('"attachmentsDir"') + '\t' +
colors.grey('Replace "@attachment" in img tags\n\t\t\t\t\twith a custom string'))
}
/**
* CLI Version output
*/
const versionOutput = () => {
console.log('0.0.2')
}
// Check if a file was given
if (process.argv.length < 3) {
console.error('No file path specified!\n')
helpOutput()
process.exit(1)
}
// Check if options are correct
if (process.argv.length >= 3) {
let infoAlreadyEnabled = false
let replaceAlreadyEnabled = false
let ignoreNext = false
for (let i = 3; i < process.argv.length; i++) {
if (process.argv[i] === '-info') {
if (infoAlreadyEnabled) {
console.error(`'-info' option cannot bet enabled twice!\n`)
helpOutput()
process.exit(1)
} else {
infoAlreadyEnabled = true
enableInfo = true
}
} else if (process.argv[i] === '-customReplace') {
if (replaceAlreadyEnabled) {
console.error(`'-customReplace' option cannot bet enabled twice!\n`)
helpOutput()
process.exit(1)
} else {
replaceAlreadyEnabled = true
if (i + 1 > process.argv.length) {
console.error(`'-customReplace' option needs a following argument!\n`)
helpOutput()
process.exit(1)
}
ignoreNext = true
replaceWith = process.argv[i + 1]
}
} else {
if (!ignoreNext) {
console.error(`Unknown option: "${colors.red(process.argv[i])}"\n`)
helpOutput()
process.exit(1)
} else {
ignoreNext = false
}
}
}
}
// Check if instead of a file help/version is wanted
if (process.argv[2] === '--help' ||
process.argv[2] === '-help' ||
process.argv[2] === 'help') {
helpOutput()
process.exit(0)
} else if (process.argv[2] === '--version' ||
process.argv[2] === '-version' ||
process.argv[2] === 'version') {
versionOutput()
process.exit(0)
}
/**
* File path file
*/
const filePath = process.argv[2]
// Check if file exists
if (!fs.existsSync(filePath)) {
console.error(`File was not found: "${colors.red(filePath)}"\n`)
helpOutput()
process.exit(1)
}
/**
* Regex to find image resources
* ```js
* const aString = '<img src="@attachment/test.svg" >' +
* '<img src="@attachment/test.png">'
* let match = regexImageResource.exec(aString)
* while (match !== null) {
* // <img src="@attachment/test.svg" >, <img src="@attachment/test.png" >
* console.log(match[1])
* match = regexImageResource.exec(aString)
* }
* ```
*/
const regexImageResource = /<img .*src="@attachment\/.*?".*>/g
/**
* Extract all matches from the file via a fs.stream (much faster
* when executing on large files)
* @param {string} filePath File that should be read
* @returns {Promise<Buffer>} Array with buffer for file to edit
*/
async function createdBufferFromFileViaStream (filePath) {
return new Promise((resolve, reject) => {
const label = `createdBufferFromFileViaStream (${filePath})`
if (enableInfo) { console.time(label) }
let buffer = null
const stream = fs.createReadStream(filePath, { encoding: 'utf8' })
stream.on('data', data => {
buffer = Buffer.from(data
.replace(regexImageResource,
(everything) => everything.replace(/@attachment/g, replaceWith))
// Remove notable information (if found at the top)
.replace(/^---[\s\S]*?---[\s]*/m, ''))
stream.destroy()
}).on('error', err => {
if (enableInfo) { console.timeEnd(label) }
reject(err)
}).on('close', () => {
if (enableInfo) { console.timeEnd(label) }
resolve(buffer)
})
})
}
/**
* Write file
* @param {string} filePath
* @param {Buffer} buffer
*/
async function writeToFile (filePath, buffer) {
return new Promise((resolve, reject) => {
const label = `writeBufferToNewFile (${filePath})`
if (enableInfo) { console.time(label) }
fs.open(filePath, 'w', function (err, fd) {
if (err) {
if (enableInfo) { console.timeEnd(label) }
return reject(err)
}
fs.write(fd, buffer, 0, buffer.length, () => { }, (err) => {
if (err) {
if (enableInfo) { console.timeEnd(label) }
return reject(err)
}
fs.close(fd, () => {
if (enableInfo) { console.timeEnd(label) }
resolve()
})
})
})
})
}
// MAIN
// Create new file for use in Typora
createdBufferFromFileViaStream(filePath)
.then(buffer => {
const newFilePath = path.join(path.dirname(filePath),
path.basename(filePath, path.extname(filePath)) +
'_typora' + path.extname(filePath))
writeToFile(newFilePath, buffer).then(() => {
console.log(`File was written: "${newFilePath}"`)
}).catch(console.error)
})
.catch(console.error)
Description:
Scraps Markdown note created with Notable for used resources to
edit it and export it to a new file that can be edited in Typora.
Example:
$ node .\notableNoteToTypora.js filePath.md -enableOptionalOption
File was written: "filePath_typora.md"
Options:
-info Get information about performance
and other things
-customReplace "attachmentsDir" Replace "@attachment" in img tags
with a custom string
title tags created modified attachments
A title
Notebooks/Test
2019-02-17T19:54:53.942Z
2019-02-19T16:27:42.872Z
test.svg

A title

Another section

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment