Skip to content
This repository was archived by the owner on Mar 9, 2021. It is now read-only.

Commit c99faba

Browse files
committed
Works with standard input.
1 parent 0da7b4d commit c99faba

File tree

6 files changed

+161
-88
lines changed

6 files changed

+161
-88
lines changed

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,6 @@ glyphhanger ./test.html --json
5555
# show results only for one or more font-family names
5656
glyphhanger ./test.html --family='Open Sans, Roboto'
5757

58-
# use much faster jsdom mode instead of headless Chrome
59-
glyphhanger ./test.html --jsdom
60-
6158
# Show version
6259
glyphhanger --version
6360

@@ -212,14 +209,22 @@ Limit results to text inside of elements that match a CSS selector
212209
glyphhanger ./test.html --cssSelector="pre, #header, .popUp". If paired with `--onlyVisible`, it will only return elements that are both visible and match the selector
213210
```
214211

215-
### Advanced: use `jsdom` Mode ⚠️
212+
### Advanced: `jsdom` Mode ⚠️
216213

217214
JSDOM mode can be useful running against static pages that don’t use a lot of JavaScript generated content. While JSDOM mode can handle some JavaScript generated content, Puppeteer mode should be the safest method for most use cases.
218215

219216
JSDOM mode will also be much faster when running against files on a local filesystem rather than URL targets.
220217

221218
Read more about [the difference between JSDOM and a full headless browser](https://github.com/jsdom/jsdom/wiki/jsdom-vs.-PhantomJS) (like the default mode that glyphhanger uses: Puppeteer/headless Chrome).
222219

220+
```sh
221+
# use faster jsdom mode instead of headless Chrome
222+
glyphhanger ./test.html --jsdom
223+
224+
# jsdom mode works with standard input too
225+
echo "this is a test" | glyphhanger ./test.html --jsdom
226+
```
227+
223228
## Troubleshooting
224229

225230
* `glyphhanger` uses Puppeteer, the headless Chrome browser. Check out the [Puppeteer Troubleshooting documentation](https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#chrome-headless-doesnt-launch).

cmd.js

Lines changed: 71 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#!/usr/bin/env node
2-
var argv = require( "minimist" )( process.argv.slice(2) );
3-
var GlyphHanger = require( "./src/GlyphHanger" );
4-
var GlyphHangerWhitelist = require( "./src/GlyphHangerWhitelist" );
5-
var GlyphHangerSubset = require( "./src/GlyphHangerSubset" );
6-
var GlyphHangerFontFace = require( "./src/GlyphHangerFontFace" );
7-
var MultipleSpiderPigs = require( "./src/MultipleUrlSpiderPig" );
2+
const argv = require( "minimist" )( process.argv.slice(2) );
3+
const chalk = require("chalk");
4+
const getStdin = require("get-stdin");
5+
const GlyphHanger = require( "./src/GlyphHanger" );
6+
const GlyphHangerWhitelist = require( "./src/GlyphHangerWhitelist" );
7+
const GlyphHangerSubset = require( "./src/GlyphHangerSubset" );
8+
const GlyphHangerFontFace = require( "./src/GlyphHangerFontFace" );
9+
const MultipleSpiderPigs = require( "./src/MultipleUrlSpiderPig" );
810
const debug = require( "debug" )( "glyphhanger:cli" );
911

1012
var whitelist = new GlyphHangerWhitelist( argv.w || argv.whitelist, {
@@ -68,34 +70,42 @@ if( argv.subset ) {
6870
// glyphhanger --subset=*.ttf --family='My Serif' -css (subset group of fonts to results for specific family and a font-face block)
6971
// glyphhanger --subset=*.ttf --output=dist/ (change the output directory for subset files)
7072

71-
if( argv.version ) {
72-
var pkg = require( "./package.json" );
73-
console.log( pkg.version );
74-
} else if( argv.help ) {
75-
gh.outputHelp();
76-
} else if( argv._ && argv._.length ) {
77-
(async function() {
78-
// Spider
79-
if( argv.spider || argv[ 'spider-limit' ] || argv[ 'spider-limit' ] === 0 ) {
80-
let sp = new MultipleSpiderPigs();
81-
sp.setLimit(argv[ 'spider-limit' ]);
82-
await sp.fetchUrls(argv._);
83-
84-
let urls = sp.getUrlsWithLimit();
85-
await sp.finish();
86-
debug( "Urls (after limit): %o", urls );
73+
(async function() {
74+
let standardInput = (await getStdin()).trim();
75+
gh.setStandardInput(standardInput);
8776

88-
await gh.fetchUrls( urls );
89-
} else {
90-
await gh.fetchUrls( argv._ );
77+
if( argv.version ) {
78+
var pkg = require( "./package.json" );
79+
console.log( pkg.version );
80+
} else if( argv.help ) {
81+
gh.outputHelp();
82+
} else if( argv._ && argv._.length || standardInput ) {
83+
// Spider
84+
try {
85+
if( argv.spider || argv[ 'spider-limit' ] || argv[ 'spider-limit' ] === 0 ) {
86+
let sp = new MultipleSpiderPigs();
87+
sp.setLimit(argv[ 'spider-limit' ]);
88+
await sp.fetchUrls( argv._ );
89+
90+
let urls = sp.getUrlsWithLimit();
91+
await sp.finish();
92+
debug( "Urls (after limit): %o", urls );
93+
94+
await gh.fetchUrls( urls );
95+
} else {
96+
await gh.fetchUrls( argv._ );
97+
}
98+
} catch(e) {
99+
console.log(chalk.red("GlyphHanger Fetch Error: "), e);
100+
process.exitCode = 1;
91101
}
92102

93103
gh.output();
94104
try {
95105
fontface.setUnicodeRange( gh.getUnicodeRange() );
96106
fontface.writeCSSFiles();
97107
} catch(e) {
98-
console.log("GlyphHangerFontFace Error: ", e);
108+
console.log(chalk.red("GlyphHangerFontFace Error: "), e);
99109
process.exitCode = 1;
100110
}
101111

@@ -104,53 +114,53 @@ if( argv.version ) {
104114
subset.subsetAll( gh.getUnicodeRange() );
105115
}
106116
} catch(e) {
107-
console.log("GlyphHangerSubset Error: ", e);
117+
console.log(chalk.red("GlyphHangerSubset Error: "), e);
108118
process.exitCode = 1;
109119
}
110120

111121
try {
112122
fontface.output();
113123
} catch(e) {
114-
console.log("GlyphHangerFontFace Error: ", e);
124+
console.log(chalk.red("GlyphHangerFontFace Error: "), e);
115125
process.exitCode = 1;
116126
}
117-
})();
118-
} else { // not using URLs
119-
if( argv.subset ) {
120-
gh.output();
127+
} else { // not using URLs
128+
if( argv.subset ) {
129+
gh.output();
130+
131+
try {
132+
// --subset with or without --whitelist
133+
subset.subsetAll( !whitelist.isEmpty() ? whitelist.getWhitelistAsUnicodes() : whitelist.getUniversalRangeAsUnicodes() );
134+
} catch(e) {
135+
process.exitCode = 1;
136+
console.log(chalk.red("GlyphHangerSubset Error: "), e);
137+
}
121138

122-
try {
123-
// --subset with or without --whitelist
124-
subset.subsetAll( !whitelist.isEmpty() ? whitelist.getWhitelistAsUnicodes() : whitelist.getUniversalRangeAsUnicodes() );
125-
} catch(e) {
126-
process.exitCode = 1;
127-
console.log("GlyphHangerSubset Error: ", e);
128-
}
139+
try {
140+
if(!whitelist.isEmpty()) {
141+
fontface.setUnicodeRange( whitelist.getWhitelistAsUnicodes());
142+
}
143+
fontface.writeCSSFiles();
144+
fontface.output();
145+
} catch(e) {
146+
process.exitCode = 1;
147+
console.log(chalk.red("GlyphHangerFontFace Error: "), e);
148+
}
149+
} else if( !whitelist.isEmpty() ) {
150+
// not subsetting, just output the code points (can convert whitelist string to code points)
151+
gh.outputUnicodes();
129152

130-
try {
131-
if(!whitelist.isEmpty()) {
153+
try {
132154
fontface.setUnicodeRange( whitelist.getWhitelistAsUnicodes());
155+
fontface.writeCSSFiles();
156+
fontface.output();
157+
} catch(e) {
158+
process.exitCode = 1;
159+
console.log(chalk.red("GlyphHangerFontFace Error: "), e);
133160
}
134-
fontface.writeCSSFiles();
135-
fontface.output();
136-
} catch(e) {
137-
process.exitCode = 1;
138-
console.log("GlyphHangerFontFace Error: ", e);
161+
} else {
162+
gh.outputHelp();
139163
}
140-
} else if( !whitelist.isEmpty() ) {
141-
// not subsetting, just output the code points (can convert whitelist string to code points)
142-
gh.outputUnicodes();
143164

144-
try {
145-
fontface.setUnicodeRange( whitelist.getWhitelistAsUnicodes());
146-
fontface.writeCSSFiles();
147-
fontface.output();
148-
} catch(e) {
149-
process.exitCode = 1;
150-
console.log("GlyphHangerFontFace Error: ", e);
151-
}
152-
} else {
153-
gh.outputHelp();
154165
}
155-
156-
}
166+
})();

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"debug": "^3.1.0",
3232
"filesize": "^3.5.11",
3333
"fs-extra": "^5.0.0",
34+
"get-stdin": "^6.0.0",
3435
"glob": "^7.1.2",
3536
"minimist": "^1.2.0",
3637
"parse-filepath": "^1.0.2",

src/GlyphHanger.js

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,15 @@ class GlyphHanger {
115115
};
116116
}
117117

118+
setStandardInput(standardInput) {
119+
this.standardInput = standardInput;
120+
this.env.setStandardInput(this.standardInput);
121+
}
122+
118123
async _fetchUrl( url ) {
119124
debug( "requesting: %o", url );
120125

121126
let page = await this.env.getPage(url);
122-
123127
if(!page) {
124128
return false;
125129
}
@@ -132,23 +136,34 @@ class GlyphHanger {
132136

133137
async fetchUrls( urls ) {
134138
let failCount = 0;
135-
for( let url of urls ) {
136-
debug("WebServer.isValidUrl(%o)", url);
137-
138-
let urlStr = url;
139-
if(this.env.requiresWebServer()) {
140-
if(!WebServer.isValidUrl(url) || url.indexOf('http://localhost:') === 0 ) {
141-
if( !this.staticServer ) {
142-
debug("Creating static server");
143-
this.staticServer = await WebServer.getStaticServer();
139+
if( !urls.length && this.standardInput ) {
140+
if( !this.env.isJSDOM() ) {
141+
throw new Error("Standard input mode requires using --jsdom");
142+
}
143+
let result = await this._fetchUrl();
144+
if( result === false ) {
145+
failCount++;
146+
}
147+
} else {
148+
for( let url of urls ) {
149+
debug("WebServer.isValidUrl(%o)", url);
150+
151+
let urlStr = url;
152+
if(this.env.requiresWebServer()) {
153+
if(!WebServer.isValidUrl(url) || url.indexOf('http://localhost:') === 0 ) {
154+
if( !this.staticServer ) {
155+
debug("Creating static server");
156+
this.staticServer = await WebServer.getStaticServer();
157+
}
144158
}
145-
}
146159

147-
urlStr = WebServer.getUrl(url);
148-
}
160+
urlStr = WebServer.getUrl(url);
161+
}
149162

150-
if( (await this._fetchUrl(urlStr)) === false ) {
151-
failCount++;
163+
let result = await this._fetchUrl(urlStr);
164+
if( result === false ) {
165+
failCount++;
166+
}
152167
}
153168
}
154169

src/GlyphHangerEnvironment.js

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const fs = require( "fs-extra" );
44
const jsdom = require("jsdom");
55
const { JSDOM } = jsdom;
66
const puppeteer = require("puppeteer");
7+
const getStdin = require('get-stdin');
78
const WebServer = require("./WebServer");
89
const debugNodes = require("debug")("glyphhanger:nodes");
910

@@ -28,17 +29,32 @@ class JSDOMEnvironment {
2829
return false;
2930
}
3031

31-
async getPage(url) {
32-
let isValidUrl = WebServer.isValidUrl(url);
33-
let method = isValidUrl ? "fromURL" : "fromFile";
32+
async getPage(url, standardInput) {
3433
let options = {
3534
runScripts: "dangerously",
3635
// do we want to load subresources? leaving off for now
37-
// resources: "usable"
38-
};
39-
if( !isValidUrl ) {
36+
// resources: "usable",
37+
4038
// https://github.com/jsdom/jsdom/issues/2304
41-
options.url = "http://localhost/";
39+
url: "http://localhost/"
40+
};
41+
42+
if( standardInput ) {
43+
if( url ) {
44+
console.log( chalk.yellow("A URL argument was passed but it was ignored. Using stdin instead.") );
45+
}
46+
if(standardInput.charAt(0) !== "<") {
47+
standardInput = `<!doctype html><html><title></title><body>${standardInput}</body></html>`;
48+
}
49+
50+
return new JSDOM(standardInput, options);
51+
}
52+
53+
let isValidUrl = WebServer.isValidUrl(url);
54+
let method = isValidUrl ? "fromURL" : "fromFile";
55+
if( isValidUrl ) {
56+
// see https://github.com/jsdom/jsdom/issues/2304 above
57+
delete options.url;
4258
}
4359

4460
let domPromise = JSDOM[method](url, options);
@@ -177,12 +193,20 @@ class GlyphHangerEnvironment {
177193
return this._env;
178194
}
179195

196+
isJSDOM() {
197+
return this.envStr === "jsdom";
198+
}
199+
200+
setStandardInput(value) {
201+
this.standardInput = value;
202+
}
203+
180204
requiresWebServer() {
181205
return this.env.requiresWebServer();
182206
}
183207

184208
async getPage(url) {
185-
return this.env.getPage(url);
209+
return this.env.getPage(url, this.standardInput);
186210
}
187211

188212
async getResults(page, options) {

test/cmdTest.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,22 @@ describe( "CLI (css)", function() {
268268

269269
assert.equal( output.toString().trim(), "U+20,U+61,U+63,U+65,U+67-69,U+6D-70,U+73,U+74" );
270270
});
271+
272+
it( "System input and --jsdom", function () {
273+
this.timeout( 10000 );
274+
let output = childProcess.execSync(`echo "<b>ih</b>" | node cmd.js --jsdom --string`, {
275+
cwd: path.resolve(__dirname, "..")
276+
});
277+
278+
assert.equal( output.toString().trim(), "hi" );
279+
});
280+
281+
it( "System input and --jsdom (not HTML, gets transformed to HTML for JSDOM)", function () {
282+
this.timeout( 10000 );
283+
let output = childProcess.execSync(`echo "ih" | node cmd.js --jsdom --string`, {
284+
cwd: path.resolve(__dirname, "..")
285+
});
286+
287+
assert.equal( output.toString().trim(), "hi" );
288+
});
271289
});

0 commit comments

Comments
 (0)