Skip to content

Commit d012292

Browse files
authored
Adds support for verbose response when checking domains
2 parents 91c1123 + a25a93e commit d012292

11 files changed

+334
-137
lines changed

__mocks__/https.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ https.get.mockImplementation((url, options, callback) => {
1010
stream.emit(
1111
"data",
1212
Buffer.from(
13-
`{"google.com": {"url":"google.com","hosted_by":"Google Inc.","hosted_by_website":"https://www.google.com","partner":null,"green":true}}`
13+
`{"google.com": {"url":"google.com","hosted_by":"Google Inc.","hosted_by_website":"https://www.google.com","partner":null,"green":true}, "pchome.com": {"url":"pchome.com","green":false} }`
1414
)
1515
);
1616
} else {

package-lock.json

-25
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/helpers/index.js

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ import {
55
FIRST_TIME_VIEWING_PERCENTAGE,
66
RETURNING_VISITOR_PERCENTAGE,
77
} from "../constants/index.js";
8+
9+
// Shared type definitions to be used across different files
10+
11+
/**
12+
* @typedef {Object} DomainCheckOptions options to control the behavior when checking a domain
13+
* @property {string} userAgentIdentifier - Optional. The app, site, or organisation that is making the request.
14+
* @property {boolean} verbose - Optional. Whether to return a verbose response.
15+
* @property {string[]} db - Optional. A database list to use for lookups.
16+
*/
17+
818
const formatNumber = (num) => parseFloat(num.toFixed(2));
919

1020
function parseOptions(options) {

src/hosting-api.js

+33-16
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,77 @@
11
"use strict";
22

33
import { getApiRequestHeaders } from "./helpers/index.js";
4+
import hostingJSON from "./hosting-json.js";
45

56
/**
6-
* Check if a string or array of domains has been provided
7+
* Check if a string or array of domains is hosted by a green web host by querying the Green Web Foundation API.
78
* @param {string|array} domain - The domain to check, or an array of domains to be checked.
8-
* @param {string} userAgentIdentifier - Optional. The app, site, or organisation that is making the request.
9+
* @param {string | DomainCheckOptions} optionsOrAgentId - Optional. An object of domain check options, or a string
10+
* representing the app, site, or organisation that is making the request.
911
*/
1012

11-
function check(domain, userAgentIdentifier) {
13+
function check(domain, optionsOrAgentId) {
14+
const options =
15+
typeof optionsOrAgentId === "string"
16+
? { userAgentIdentifier: optionsOrAgentId }
17+
: optionsOrAgentId;
18+
19+
if (options?.db && options.verbose) {
20+
throw new Error("verbose mode cannot be used with a local lookup database");
21+
}
1222
// is it a single domain or an array of them?
1323
if (typeof domain === "string") {
14-
return checkAgainstAPI(domain, userAgentIdentifier);
24+
return checkAgainstAPI(domain, options);
1525
} else {
16-
return checkDomainsAgainstAPI(domain, userAgentIdentifier);
26+
return checkDomainsAgainstAPI(domain, options);
1727
}
1828
}
1929

2030
/**
2131
* Check if a domain is hosted by a green web host by querying the Green Web Foundation API.
2232
* @param {string} domain - The domain to check.
23-
* @param {string} userAgentIdentifier - Optional. The app, site, or organisation that is making the request.
24-
* @returns {boolean} - A boolean indicating whether the domain is hosted by a green web host.
33+
* @param {DomainCheckOptions} options
34+
* @returns - A boolean indicating whether the domain is hosted by a green web host if `options.verbose` is false,
35+
* otherwise an object representing the domain host information.
2536
*/
26-
async function checkAgainstAPI(domain, userAgentIdentifier) {
37+
async function checkAgainstAPI(domain, options = {}) {
2738
const req = await fetch(
2839
`https://api.thegreenwebfoundation.org/greencheck/${domain}`,
2940
{
30-
headers: getApiRequestHeaders(userAgentIdentifier),
41+
headers: getApiRequestHeaders(options.userAgentIdentifier),
3142
}
3243
);
44+
if (options?.db) {
45+
return hostingJSON.check(domain, options.db);
46+
}
3347
const res = await req.json();
34-
return res.green;
48+
return options.verbose ? res : res.green;
3549
}
3650

3751
/**
3852
* Check if an array of domains is hosted by a green web host by querying the Green Web Foundation API.
3953
* @param {array} domains - An array of domains to check.
40-
* @param {string} userAgentIdentifier - Optional. The app, site, or organisation that is making the request.
41-
* @returns {array} - An array of domains that are hosted by a green web host.
54+
* @param {DomainCheckOptions} options
55+
* @returns - An array of domains that are hosted by a green web host if `options.verbose` is false,
56+
* otherwise a dictionary of domain to host information.
4257
*/
4358

44-
async function checkDomainsAgainstAPI(domains, userAgentIdentifier) {
59+
async function checkDomainsAgainstAPI(domains, options = {}) {
4560
try {
4661
const apiPath = "https://api.thegreenwebfoundation.org/v2/greencheckmulti";
4762
const domainsString = JSON.stringify(domains);
4863

4964
const req = await fetch(`${apiPath}/${domainsString}`, {
50-
headers: getApiRequestHeaders(userAgentIdentifier),
65+
headers: getApiRequestHeaders(options.userAgentIdentifier),
5166
});
5267

5368
const allGreenCheckResults = await req.json();
5469

55-
return greenDomainsFromResults(allGreenCheckResults);
70+
return options.verbose
71+
? allGreenCheckResults
72+
: greenDomainsFromResults(allGreenCheckResults);
5673
} catch (e) {
57-
return [];
74+
return options.verbose ? {} : [];
5875
}
5976
}
6077

src/hosting-api.test.js

+62
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,33 @@ describe("hostingAPI", () => {
4040
);
4141
expect(res).toEqual(true);
4242
});
43+
it("handles the verbose=true option", async () => {
44+
fetch.mockImplementation(() =>
45+
Promise.resolve({
46+
json: () =>
47+
Promise.resolve({
48+
url: "google.com",
49+
hosted_by: "Google Inc.",
50+
hosted_by_website: "https://www.google.com",
51+
green: true,
52+
}),
53+
})
54+
);
55+
const res = await hosting.check("google.com", { verbose: true });
56+
expect(fetch).toHaveBeenCalledTimes(1);
57+
expect(fetch).toHaveBeenLastCalledWith(
58+
expect.any(String),
59+
expect.objectContaining({
60+
headers: { "User-Agent": "co2js/1.2.34 " },
61+
})
62+
);
63+
expect(res).toMatchObject({
64+
green: true,
65+
hosted_by: "Google Inc.",
66+
hosted_by_website: "https://www.google.com",
67+
url: "google.com",
68+
});
69+
});
4370
});
4471
describe("implicitly checking multiple domains with #check", () => {
4572
it("using the API", async () => {
@@ -69,6 +96,41 @@ describe("hostingAPI", () => {
6996
);
7097
expect(res).toContain("google.com");
7198
});
99+
it("handles the verbose=true option", async () => {
100+
fetch.mockImplementation(() =>
101+
Promise.resolve({
102+
json: () =>
103+
Promise.resolve({
104+
"google.com": {
105+
url: "google.com",
106+
hosted_by: "Google Inc.",
107+
hosted_by_website: "https://www.google.com",
108+
green: true,
109+
},
110+
"kochindustries.com": {
111+
url: "kochindustries.com",
112+
green: false,
113+
},
114+
}),
115+
})
116+
);
117+
const res = await hosting.check(["google.com", "kochindustries.com"], {
118+
verbose: true,
119+
});
120+
expect(fetch).toHaveBeenCalledTimes(1);
121+
expect(res).toEqual({
122+
"google.com": expect.objectContaining({
123+
green: true,
124+
hosted_by: "Google Inc.",
125+
hosted_by_website: "https://www.google.com",
126+
url: "google.com",
127+
}),
128+
"kochindustries.com": expect.objectContaining({
129+
url: "kochindustries.com",
130+
green: false,
131+
}),
132+
});
133+
});
72134
});
73135
});
74136
/* eslint-enable jest/no-disabled-tests */

src/hosting-json.js

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"use strict";
2+
3+
/**
4+
* Check if a string or array of domains has been provided
5+
* @param {string|array} domain - The domain to check, or an array of domains to be checked.
6+
*/
7+
async function check(domain, db) {
8+
// is it a single domain or an array of them?
9+
if (typeof domain === "string") {
10+
return checkInJSON(domain, db);
11+
} else {
12+
return checkDomainsInJSON(domain, db);
13+
}
14+
}
15+
16+
/**
17+
* Check if a domain is hosted by a green web host by querying the database.
18+
* @param {string} domain - The domain to check.
19+
* @param {object} db - The database to check against.
20+
* @returns {boolean} - A boolean indicating whether the domain is hosted by a green web host.
21+
*/
22+
function checkInJSON(domain, db) {
23+
if (db.indexOf(domain) > -1) {
24+
return true;
25+
}
26+
return false;
27+
}
28+
29+
/**
30+
* Extract the green domains from the results of a green check.
31+
* @param {object} greenResults - The results of a green check.
32+
* @returns {array} - An array of domains that are hosted by a green web host.
33+
*/
34+
function greenDomainsFromResults(greenResults) {
35+
const entries = Object.entries(greenResults);
36+
const greenEntries = entries.filter(([key, val]) => val.green);
37+
38+
return greenEntries.map(([key, val]) => val.url);
39+
}
40+
41+
/**
42+
* Check if an array of domains is hosted by a green web host by querying the database.
43+
* @param {array} domains - An array of domains to check.
44+
* @param {object} db - The database to check against.
45+
* @returns {array} - An array of domains that are hosted by a green web host.
46+
*/
47+
function checkDomainsInJSON(domains, db) {
48+
let greenDomains = [];
49+
50+
for (let domain of domains) {
51+
if (db.indexOf(domain) > -1) {
52+
greenDomains.push(domain);
53+
}
54+
}
55+
return greenDomains;
56+
}
57+
58+
/**
59+
* Find the provided information a string or array of domains
60+
* @param {string|array} domain - The domain to check, or an array of domains to be checked.
61+
*/
62+
function find(domain, db) {
63+
// is it a single domain or an array of them?
64+
if (typeof domain === "string") {
65+
return findInJSON(domain, db);
66+
} else {
67+
return findDomainsInJSON(domain, db);
68+
}
69+
}
70+
71+
/**
72+
* Check if a domain is hosted by a green web host by querying the database.
73+
* @param {string} domain - The domain to check.
74+
* @param {object} db - The database to check against.
75+
* @returns {object} - An object representing the domain provided host information.
76+
*/
77+
function findInJSON(domain, db) {
78+
if (db.indexOf(domain) > -1) {
79+
return domain;
80+
}
81+
return {
82+
url: domain,
83+
green: false,
84+
};
85+
}
86+
87+
/**
88+
* Check if an array of domains is hosted by a green web host by querying the database.
89+
* @param {array} domains - An array of domains to check.
90+
* @param {object} db - The database to check against.
91+
* @returns {array} - A dictionary of domain to provided host information.
92+
*/
93+
function findDomainsInJSON(domains, db) {
94+
const result = {};
95+
for (let domain of domains) {
96+
result[domain] = findInJSON(domain, db);
97+
}
98+
return result;
99+
}
100+
101+
module.exports = {
102+
check,
103+
greenDomainsFromResults,
104+
find,
105+
};

0 commit comments

Comments
 (0)