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.