How to load multiple YAML files at once in JavaScript

Viewed 1754

I wrote a Ruby script that splits one large YAML file (called travel.yaml), which contains a list of country keys and info, into separate files for every country.

data = YAML.load(File.read('./src/constants/travel.yaml'))

data.fetch('countries').each do |key, value|
  File.open("./src/constants/countries/#{key}.yaml", 'w') { |file| file.write({ key => value }.to_yaml) }
end

Making each file look like this:

---
BA:
  sources:
    domestic:
    - Wearing masks and social distancing (a minimum of 2 metres) are [mandatory in
      all public places](https://www.oecd.org/south-east-europe/COVID-19-Crisis-in-Bosnia-and-Herzegovina.pdf).
    inbound:
    - The BiH Council of Ministers has announced that it will allow entry to the citizens
      of Croatia, Serbia, and Montenegro as of June 1, 2020. There is [still a ban
      to entry for non-resident foreign nationals.](https://ba.usembassy.gov/covid-19-information/)
    visa_quarantine:
    - Both the Republika Srpska and the Federation have [abolished self-isolation
      measures for people entering BiH.](https://ba.usembassy.gov/covid-19-information/).
  travel:
    domestic: partial
    inbound: partial
    inbound_allowed:
    - HR
    - RS
    - ME

Before splitting travel.yaml, this is how it was consumed:

import TravelDefaults from '@/constants/travel.yaml';

export const Travel = TravelDefaults;

const { countries, checked_on } = Travel;

I’d now like to load all the separate YAML files at once and consume those instead (without having to import each file separately).

How can I do that? This has to be done in VUE and with Typescript.

2 Answers
const yaml = require('js-yaml');
const mergeYaml = require('merge-yaml');
const fs = require('fs');

const travelMerger = () => {
  const basePath = './src/constants/';

  const countryFiles = fs.readdirSync(`${basePath}countries/`);

  const filesWithDir = countryFiles.map((file) => `${basePath}countries/${file}`);

  const countriesYaml = mergeYaml(filesWithDir);

  const yamlStr = yaml.safeDump(countriesYaml);

  fs.writeFileSync(`${basePath}travelMerged.yaml`, yamlStr, 'utf8');
};

module.exports = travelMerger;

This works, but unfortunately, not in Vue with TypeScript.

If you don't mind a compile-time static solution, you can do it using webpack require.context (docs) and a yaml loader.

Example

Using vue-cli-plugin-yaml.

Assuming that your yml files are located in src/constants/countries/*.yml you can use the following code to get each JS object from the yaml files using a computed method named countries:

<template>
  <div id="app">
    <div
      v-for="country in countries"
      :key="country.key"
      class="country"
    >
      <h1>{{country.key}}</h1>
      <hr />
      <h2>{{country.sources.domestic[0]}}</h2>
    </div>
  </div>
</template>

<script lang="ts">
import { Vue } from 'vue-property-decorator'
export default class App extends Vue {
  get countries () {
    const requireContext = require.context(
      './constants/countries',
      true,
      /(.*)\.yml/
    )
    return requireContext.keys().map((fileName) => {
      const key: string = fileName.split('.')[1].replace('/', '')
      return {
        key: key,
        ...requireContext(fileName)[key]
      }
    })
  }
}
</script>

<style>
#app {
  text-align: center;
  margin-top: 60px;
}
.country{
  border:1px solid black;
  margin:20px;
}
</style>

example with some dummy files

Related