Ok, so I'm learning javascript (coming from c ) by writing a utility that takes in .md (markdown) files and parses/transforms the file to an html then to a json object, then writes that object to an existing json file in a format that follows my specification.
to be clear see the following pipeline:
loop through a directory of .md files -> push each file through a parse/transform phase that turns markdown to html -> push the html and parsed data to a json file
please note that I have most of the logic completed, however, I need help with a formatting issue...please read the full post before closing or answering. Thank you!
main logic of the pipeline:
export function transformMdtoHtmltoJson(dest, post) {
const file = matter.read(post);
const title = file.data.title;
const date = file.data.date;
const description = file.data.description;
const socials = file.data.socials;
unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify)
.process(file.content)
.then(
(result) => {
toJson(dest, title, date, description, result.value, socials);
},
(err) => {
throw err;
}
);
}
My plugin to write the json to an existing file:
class Data {
constructor(title, date, description, content, socials) {
this.title = title;
this.date = date;
this.description = description;
this.content = content;
this.socials = socials;
}
}
function createNewMember(title, date, description, content, socials) {
let newMemer = new Data(title, date, description, content, socials);
let result = {};
return result = {
"title": newMemer.title,
"date": newMemer.date,
"description": newMemer.description,
"content": newMemer.content,
"socials": newMemer.socials
}
}
export async function toJson(inFile, title, data, description, content, socials) {
const rl = readline.createInterface({
input: fs.createReadStream(inFile),
crlfDelay: Infinity,
});
const lines = [];
for await (const line of rl) {
lines.push(line);
}
let object = createNewMember(title, data, description, content, socials);
lines.push(JSON.stringify(object));
let string = lines.join('') ',';
writeFile(inFile, string);
}
function writeFile(inFile, data) {
fs.writeFile(inFile, data, { flag: "a " }, (err) => {
if (err) throw err;
console.log("The file has been saved!");
}
);
}
my inputs:
a directory of posts
~/path/to/posts/post1.md
~/path/to/posts/post2.md
~/path/to/posts/post3.md
contents of post (the same for each to make things easy)
---
title: Hello this is a test
date: 05/04/2022
description: this is a test
socials:
---
# Hello
## subhello
my target: ~/path/to/post.json
my entry point function:
const postDir = path.join(process.cwd(), 'posts');
const destDir = path.join(process.cwd(), '_data');
const jsonFile = 'post.json';
const fileNames = fs.readdirSync(postDir);
async function generatePosts(fileNames, postDir, destDir, jsonFile) {
fileNames.forEach( (fileName) => {
const fullPath = path.join(postDir, fileName);
const destPath = path.join(destDir, jsonFile)
transformMdtoHtmltoJson(destPath, fullPath);
});
}
generatePosts(fileNames, postDir, destDir, jsonFile);
my output: ~/path/to/post.json
{
"title":"Hello this is a test",
"date":"05/04/2022",
"description":"this is a test",
"content":"<h1>Hello</h1>\n<h2>subhello</h2>",
"socials":null},
{
"title":"Hello this is a test",
"date":"05/04/2022",
"description":"this is a test",
"content":"<h1>Hello</h1>\n<h2>subhello</h2>",
"socials":null},
{"title":"Hello this is a test",
"date":"05/04/2022",
"description":"this is a test",
"content":"<h1>Hello</h1>\n<h2>subhello</h2>",
"socials":null
},
What I want to do is wrap this output in [ ] brackets so that I can loop through them as an array.
Desired output:
[
{
"title":"Hello this is a test",
"date":"05/04/2022",
"description":"this is a test",
"content":"<h1>Hello</h1>\n<h2>subhello</h2>",
"socials":null},
{
"title":"Hello this is a test",
"date":"05/04/2022",
"description":"this is a test",
"content":"<h1>Hello</h1>\n<h2>subhello</h2>",
"socials":null},
{"title":"Hello this is a test",
"date":"05/04/2022",
"description":"this is a test",
"content":"<h1>Hello</h1>\n<h2>subhello</h2>",
"socials":null
},
]
I have tried several ways, but they all just wrap each individual post with [ ] resulting in
[{
"title":"Hello this is a test",
"date":"05/04/2022",
"description":"this is a test",
"content":"<h1>Hello</h1>\n<h2>subhello</h2>",
"socials":null}],
[{
"title":"Hello this is a test",
"date":"05/04/2022",
"description":"this is a test",
"content":"<h1>Hello</h1>\n<h2>subhello</h2>",
"socials":null}],
[{"title":"Hello this is a test",
"date":"05/04/2022",
"description":"this is a test",
"content":"<h1>Hello</h1>\n<h2>subhello</h2>",
"socials":null
}],
Which is not what I want. I had thought that maybe doing this with callbacks would be the solution but I have not been able to get it right. Please help.
Here is a link to the github repo https://github.com/giannicrivello/MarkdownToHtmlToJson
CodePudding user response:
I think you might have went about it the wrong way. From what I understand from your code (with libraries i'm not familiar with), what you're doing is writing your file for each .md file you have, might not be the most efficient.
What I would do so you don't have to refactor what you've done:
export async function toJson(inFile, title, data, description, content, socials) {
const buffer = fs.readFileSync(inFile);
// Maybe "buffer.toString() ?? '[]';", not sure if that works
// This is done to instanciate an empty array if the file is empty
const fileContent = buffer.toString() ? buffer.toString() : '[]';
// Parses the json into an array of objects.
// (Obviously only works if the json file is empty or an array at root)
var arrayOfObjects = JSON.parse(fileContent);
// Puts your object at begging of the array
// might as well use .push() if you want it at then end
arrayOfObjects.unshift({
title,
data,
description,
content,
socials,
});
// I REALLY recommend you use those extra arguments (null, 2)
// or similar ones so your file don't look too wierd reading it
writeFile(inFile, JSON.stringify(fullObjectArray, null, 2));
}
This may not work since I couldn't really try what you've done, didn't know how to download the packages, but it should lead you in the right way to fix what's going wrong for you :)
EDIT: While ready back what you did I noticed that both the function createNewMember
and class Data
could be removed and replaced with a basic "Object declaration" in your toJson
function. You could possible keep your Data class if you intended to re-use it elsewhere...
CodePudding user response:
There is a loop in generatePosts
... I think that is where you need to wite the open/close brackets to file.
async function generatePosts(fileNames, postDir, destDir, jsonFile) {
const destPath = path.join(destDir, jsonFile)
// Opening bracket
writeFile(destPath, "[")
fileNames.forEach( (fileName) => {
const fullPath = path.join(postDir, fileName);
//const destPath = path.join(destDir, jsonFile)
transformMdtoHtmltoJson(destPath, fullPath);
});
// Closing bracket
writeFile(destPath, "]")
}