Home > Back-end >  Writing an object to an existing json file and wrapping the contents with '[ ]'
Writing an object to an existing json file and wrapping the contents with '[ ]'

Time:06-06

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, "]")
}
  • Related