-1

I'm making multiple calls to the server and creating pages and posts in yaml format from the API in my gulpfile. The functions seem similar enough that I could just make one function for all of them.

Where I'm getting hung up is when creating the object for each item since jsonObj can't be defined outside of the XMLHttpRequest

Here's my code:

function collectLoop(slug, tempDir, destDir, args) {
  const newObject = args;
  fs.writeFile(`${tempDir}${slug}.json`,
  JSON.stringify(newObject), function (err) {
    if (err) throw err;
  });
  gulp.src(`${tempDir}${slug}.json`)
    .pipe(jsonToYaml({ safe: true}))
    .pipe(gulp.dest(destDir));
};


/*********************************************************************/
/******************************* PAGES *******************************/
/*********************************************************************/

function pageCollection(url, tempDir, destDir) {
  const xhr = new XMLHttpRequest();
  xhr.onreadystatechange = () => {
    if (xhr.readyState === 4 && xhr.status === 200) {
      const jsonObj = JSON.parse(xhr.responseText);
      checkDir(tempDir);
      checkDir(destDir);
      for (let i = 0; i < jsonObj.length; i += 1) {
        let hero_heading = false;
        let hero_subheading = false;

        if(jsonObj[i].acf.hero != undefined) {
          hero_heading = jsonObj[i].acf.hero.heading;
          hero_subheading = jsonObj[i].acf.hero.subheading;
        }
        collectLoop(jsonObj[i].slug, tempDir, destDir, {
          "obj_id" : jsonObj[i].id,
          "title" : jsonObj[i].title.rendered,
          "slug" : jsonObj[i].slug,
          "modified" : jsonObj[i].modified,
          "featured_image" : {
            "large" : jsonObj[i]._embedded['wp:featuredmedia'][0].source_url,
            "small" : jsonObj[i]._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url,
          },
          "settings" : {
            "contact_box" : jsonObj[i].acf.contact_box,
            "footer_map" : jsonObj[i].acf.map,
            "hero_banner" : jsonObj[i].acf.hero_banner,
          },
          "hero" : {
            "heading" : hero_heading,
            "subheading" : hero_subheading,
          },
          "contact_form" : jsonObj[i].acf.contact_form,
          "excerpt" : jsonObj[i].acf.excerpt,
          "content" : jsonObj[i].content.rendered,
        });
      }
    }
  };
  xhr.open('GET', url);
  xhr.send();
}

/*********************************************************************/
/******************************* POSTS *******************************/
/*********************************************************************/

function postCollection(url, tempDir, destDir) {
  const xhr = new XMLHttpRequest();
  xhr.onreadystatechange = () => {
    if (xhr.readyState === 4 && xhr.status === 200) {
      const jsonObj = JSON.parse(xhr.responseText);
      checkDir(tempDir);
      checkDir(destDir);
      for (let i = 0; i < jsonObj.length; i += 1) {
        collectLoop(jsonObj[i].slug, tempDir, destDir, {
          "obj_id" : jsonObj[i].id,
          "title" : jsonObj[i].title.rendered,
          "slug" : jsonObj[i].slug,
          "date" : jsonObj[i].date,
          "modified" : jsonObj[i].modified,
          "featured_image" : {
            "large" : jsonObj[i]._embedded['wp:featuredmedia'][0].source_url,
            "small" : jsonObj[i]._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url,
          },
          "excerpt" : jsonObj[i].excerpt.rendered,
          "content" : jsonObj[i].content.rendered,
        });
      }
    }
  };
  xhr.open('GET', url);
  xhr.send();
}

1 Answers1

0

This should maybe be posted in https://codereview.stackexchange.com and not on stackoverflow. But I going to try answer this anyway

You could create a Functions that return a function

Here is probably what I would have done.

  • use fetch instead of XMLHttpRequest
  • use async/await to avoid some callback hell
  • use for..of loop to avoid jsonObj[i] all the time
  • use Object.assign to take the default object you do in all requests and use the object returned by the mapping fn

(PS: untested)

function collectLoop(slug, tempDir, destDir, args) {
  const newObject = args
  const file = `${tempDir}${slug}.json`

  fs.writeFile(file, JSON.stringify(newObject), err => {
    if (err) throw err
  })

  gulp.src(file)
    .pipe(jsonToYaml({ safe: true }))
    .pipe(gulp.dest(destDir))
}

// Get is a function that returns another function
const get = (() => {
  async function get (map, url, tempDir, destDir) {
    const res = await fetch(url)
    const jsonObj = await res.json()

    checkDir(tempDir)
    checkDir(destDir)

    for (let item of jsonObj) {
      // Default for everything
      collectLoop(item.slug, tempDir, destDir, Object.assign({
        obj_id: item.id,
        title: item.title.rendered,
        slug: item.slug,
        date: item.date,
        modified: item.modified,
        featured_image: {
          large: item._embedded['wp:featuredmedia'][0].source_url,
          small: item._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url,
        },
        excerpt: item.excerpt.rendered,
        content: item.content.rendered
      }, map(jsonObj)))
    }
  }

  return (map = () => {}) => (...args) => get(map, ...args)
})()


const postCollection = get() // no mapping needed, dose the default
const pageCollection = get(item => ({ // This is our mapping fn
  settings: {
    contact_box: item.acf.contact_box,
    footer_map: item.acf.map,
    hero_banner: item.acf.hero_banner,
  },
  hero: {
    heading: item.acf.hero ? item.acf.hero.heading : false,
    subheading: item.acf.hero ? item.acf.hero.subheading : false
  },
  contact_form: item.acf.contact_form
}))
Endless
  • 34,080
  • 13
  • 108
  • 131