简体   繁体   中英

Get objects from js files read as strings and process into a single file with gulp

I'm trying to read in TypographyJS files with Gulp to build a list of the fonts used to enable easy downloading of the relevant Google Fonts.

So far my task looks like this:

gulp.task('buildFontListFile', function (event) {
  return gulp.src(`node_modules/+(typography-theme*)/dist/index.js`)
    .pipe(debug({title: 'typography-theme:'}))
    .pipe(gulp.dest('gulpTest/fonts'));
});

So I'm properly targeting the files I need, but currently just dumping copies into a new directory. The files I'm reading look like this:

'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});


var theme = {
  title: 'Noriega',
  baseFontSize: '18px',
  baseLineHeight: 1.61,
  headerFontFamily: ['Lato', 'sans-serif'],
  bodyFontFamily: ['Lato', 'sans-serif'],
  bodyWeight: 400,
  headerWeight: 700,
  boldWeight: 700,
  googleFonts: [{
    name: 'Lato',
    styles: ['400', '700']
  }],
  scaleRatio: 1.618
};
exports.default = theme;

What I need to do is grab the googleFonts key off this default export and process each entry into a line that looks like this:

Lato:400,700&subset=latin

Outputting the keys' contents in that format should be easy enough, but reading the contents of the file is what I can't figure out currently.

What's the best way to go about reading the contents of these files and doing some processing before finally outputting a file that looks something like this?

Lato:400,700&subset=latin
Source+Sans+Pro:200,400,700&subset=latin,latin-ext

Try this:

const gulp = require("gulp");
const glob = require('glob');
const fs = require('fs');

gulp.task('default', function () {

  // like gulp.src but makes it easy to work on individual files one at a time
  glob("node_modules/+(typography-theme*)/dist/index.js", function (er, files) {

    // used later to avoid an extra newline after the last entry added
    const numFiles = files.length;
    let thisFileNum = 1;

    files.forEach(file => {

      const contents = fs.readFileSync(file, "utf8");

      // look for "name: 'Lato',"
      let fontName = contents.match(/name:\s*'(.*)'/);

      // look for "styles: ['400', '700']"
      let fontStyle = contents.match(/styles:\s*\['(.*)'\]/);

      // get rid of the ' and , in fontStyle [the regexp returns ""'400', '700']""
      fontStyle = fontStyle[1].replace(/,|'/g, "");

      // in fontNames like "Souce Sans Pro", replace the spaces with +'s
      fontName = fontName[1].replace(/\s+/g, "+");

      // in fontStyles like "200 400 700", replace the spaces with ,'s
      fontStyle = fontStyle.replace(/\s+/g, ",");

      // now build the next line to append to the file 
      let line = `${fontName}:${fontStyle}&subset=latin`;
      // I don't know where you got the 'latin-ext' on one of your fonts

      // if the last file, omit the newline
      if (thisFileNum === numFiles) {
        fs.appendFileSync('modified.txt', line);
      }
      else {
        fs.appendFileSync('modified.txt', line + '\n');
      }

      thisFileNum++;
    });
  });
});

I don't know that the order of the new file entries is guaranteed.

[ Second answer ]

Here is another version that uses a concept I thought about using on the first answer but didn't get working until later. If the theme objects (which are returned as strings by fs.readFileSync ) could be converted back to regular javascript objects we could use dot notation to access all its properties.

But we don't want to use eval , the Function(string) method works nicely as long as we append a return object to the string. See MDN: how to replace eval with Function()

And the code would be a little more robust by getting the entire theme string instead of various lines within the file. A bonus is that the object.properties calls return a nicer format than the other answer version does. No quotes and commas that need to be removed.

const gulp = require("gulp");
const glob = require('glob');
const fs = require('fs');

gulp.task('default', function () {

  // like gulp.src but makes it easy to work on individual files one at a time
  glob("./+(folder*)/index.js", function (er, files) {

    // used later to avoid an extra newline after the last entry added
    const numFiles = files.length;
    let thisFileNum = 1;

    files.forEach(file => {

      const contents = fs.readFileSync(file, "utf8");

      // get the entire theme object, using the dotall flag to include newlines
      let themeVarString = contents.match(/(var theme.*)exports/s)[1];

      // Since the theme object is now a string, we need to convert it to a javascript object again
      //   so we can access its values easily.
      //   But don't use eval, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
      //   Use Function() instead, but it should return the object so append "return theme;"
      //     And call it immediately () so it reurns the theme object (as an javascript object!)

      let themeObject = Function(`${themeVarString}return theme;`)();

      // now themeObject is a regular javascript object, we can access its properties with dot notation
      // nice, name is returned as Lato or Source Sans Pro : no quotes
      // make Source Sans Pro into Source+Sans+Pro
      let fontName = themeObject.googleFonts[0].name.replace(/\s+/g, "+");

      // and the styles are returned as 200,400,700 : no quotes or spaces!

        // now build the next line to append to the file 
      let line = `${fontName}:${themeObject.googleFonts[0].styles}&subset=latin`;
        // I don't know where you got the 'latin-ext' on one of your fonts

        // if the last file, omit the newline
      if (thisFileNum === numFiles) {
        fs.appendFileSync('modified.txt', line);
      }
      else {
        fs.appendFileSync('modified.txt', line + '\n');

      }

      thisFileNum++;
    });
  });
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM