@tgwf/co2 0.9.0-0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/.esbuild.browser.js +11 -0
  2. package/.esbuild.esm.js +25 -0
  3. package/.esbuild.node.js +16 -0
  4. package/.gitpod.yml +8 -0
  5. package/CHANGELOG.md +13 -2
  6. package/README.md +29 -66
  7. package/dist/cjs/1byte.js +52 -0
  8. package/dist/cjs/1byte.js.map +7 -0
  9. package/dist/cjs/1byte.test.js +27 -0
  10. package/dist/cjs/1byte.test.js.map +7 -0
  11. package/dist/cjs/co2.js +116 -0
  12. package/dist/cjs/co2.js.map +7 -0
  13. package/dist/cjs/co2.test.js +244 -0
  14. package/dist/cjs/co2.test.js.map +7 -0
  15. package/dist/cjs/constants/file-size.js +27 -0
  16. package/dist/cjs/constants/file-size.js.map +7 -0
  17. package/dist/cjs/constants/index.js +27 -0
  18. package/dist/cjs/constants/index.js.map +7 -0
  19. package/dist/cjs/helpers/index.js +24 -0
  20. package/dist/cjs/helpers/index.js.map +7 -0
  21. package/dist/cjs/hosting-api.js +64 -0
  22. package/dist/cjs/hosting-api.js.map +7 -0
  23. package/dist/cjs/hosting-api.test.js +47 -0
  24. package/dist/cjs/hosting-api.test.js.map +7 -0
  25. package/dist/cjs/hosting-database.node.test.js +36 -0
  26. package/dist/cjs/hosting-database.node.test.js.map +7 -0
  27. package/dist/cjs/hosting-json.node.js +73 -0
  28. package/dist/cjs/hosting-json.node.js.map +7 -0
  29. package/dist/cjs/hosting-json.node.test.js +43 -0
  30. package/dist/cjs/hosting-json.node.test.js.map +7 -0
  31. package/dist/cjs/hosting-node.js +78 -0
  32. package/dist/cjs/hosting-node.js.map +7 -0
  33. package/dist/cjs/hosting.js +36 -0
  34. package/dist/cjs/hosting.js.map +7 -0
  35. package/dist/cjs/hosting.test.js +74 -0
  36. package/dist/cjs/hosting.test.js.map +7 -0
  37. package/dist/cjs/index-node.js +29 -0
  38. package/dist/cjs/index-node.js.map +7 -0
  39. package/dist/cjs/index.js +31 -0
  40. package/dist/cjs/index.js.map +7 -0
  41. package/dist/cjs/package.json +3 -0
  42. package/dist/cjs/sustainable-web-design.js +151 -0
  43. package/dist/cjs/sustainable-web-design.js.map +7 -0
  44. package/dist/cjs/sustainable-web-design.test.js +85 -0
  45. package/dist/cjs/sustainable-web-design.test.js.map +7 -0
  46. package/dist/esm/1byte.js +32 -0
  47. package/dist/esm/1byte.test.js +11 -0
  48. package/dist/esm/co2.js +93 -0
  49. package/{src → dist/esm}/co2.test.js +27 -88
  50. package/dist/esm/constants/file-size.js +7 -0
  51. package/dist/esm/constants/index.js +4 -0
  52. package/dist/esm/helpers/index.js +4 -0
  53. package/dist/esm/hosting-api.js +41 -0
  54. package/dist/esm/hosting-api.test.js +31 -0
  55. package/{src/hosting-database.test.js → dist/esm/hosting-database.node.test.js} +7 -18
  56. package/{src/hosting-json.test.js → dist/esm/hosting-json.node.test.js} +4 -21
  57. package/dist/esm/hosting.js +13 -0
  58. package/{src → dist/esm}/hosting.test.js +10 -30
  59. package/dist/esm/index.js +8 -0
  60. package/dist/esm/package.json +3 -0
  61. package/dist/esm/sustainable-web-design.js +128 -0
  62. package/{src → dist/esm}/sustainable-web-design.test.js +25 -37
  63. package/fixup +19 -0
  64. package/package.json +38 -17
  65. package/public/index.html +58 -0
  66. package/public/index.js +2 -0
  67. package/public/index.js.map +7 -0
  68. package/src/1byte.js +2 -3
  69. package/src/co2.js +9 -17
  70. package/src/constants/file-size.js +2 -2
  71. package/src/constants/index.js +2 -2
  72. package/src/helpers/index.js +1 -3
  73. package/src/hosting-api.js +23 -43
  74. package/src/{hosting-json.js → hosting-json.node.js} +9 -11
  75. package/src/hosting-node.js +94 -0
  76. package/src/hosting.js +6 -28
  77. package/src/index-node.js +4 -0
  78. package/src/index.js +4 -6
  79. package/src/sustainable-web-design.js +37 -11
  80. package/.eslintrc.json +0 -21
  81. package/.github/workflows/unittests.yml +0 -26
  82. package/data/Lean-ICT-Materials-1byte-Model-2018.xlsx +0 -0
  83. package/data/Lean-ICT-Materials-Forecast-Model-2018.xlsx +0 -0
  84. package/data/fixtures/tgwf.har +0 -6107
  85. package/data/fixtures/url2green.test.db +0 -0
  86. package/data/fixtures/url2green.test.json +0 -1
  87. package/data/fixtures/url2green.test.json.gz +0 -0
  88. package/images/swd-energy-usage.png +0 -0
  89. package/src/1byte.test.js +0 -17
  90. package/src/green-byte.js +0 -26
  91. package/src/hosting-api.test.js +0 -37
@@ -1,31 +1,15 @@
1
1
  "use strict";
2
-
3
- const hosting = require("./hosting-json");
4
- const path = require("path");
5
-
2
+ import hosting from "./hosting-json.node.js";
3
+ import path from "path";
6
4
  describe("hostingJSON", () => {
7
- const jsonPath = path.resolve(
8
- __dirname,
9
- "..",
10
- "data",
11
- "fixtures",
12
- "url2green.test.json"
13
- );
14
- const jsonPathGz = path.resolve(
15
- __dirname,
16
- "..",
17
- "data",
18
- "fixtures",
19
- "url2green.test.json.gz"
20
- );
5
+ const jsonPath = path.resolve(__dirname, "..", "data", "fixtures", "url2green.test.json");
6
+ const jsonPathGz = path.resolve(__dirname, "..", "data", "fixtures", "url2green.test.json.gz");
21
7
  describe("checking a single domain with #check", () => {
22
8
  test("against the list of domains as JSON", async () => {
23
9
  const db = await hosting.loadJSON(jsonPath);
24
10
  const res = await hosting.check("google.com", db);
25
11
  expect(res).toEqual(true);
26
12
  });
27
- });
28
- describe("checking a single domain with #check", () => {
29
13
  test("against the list of domains as JSON loaded from a gzipped JSON", async () => {
30
14
  const db = await hosting.loadJSON(jsonPathGz);
31
15
  const res = await hosting.check("google.com", db);
@@ -36,7 +20,6 @@ describe("hostingJSON", () => {
36
20
  test("against the list of domains as JSON", async () => {
37
21
  const db = await hosting.loadJSON(jsonPath);
38
22
  const domains = ["google.com", "kochindustries.com"];
39
-
40
23
  const res = await hosting.check(domains, db);
41
24
  expect(res).toContain("google.com");
42
25
  });
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ import debugFactory from "debug";
3
+ const log = debugFactory("tgwf:hosting");
4
+ import hostingAPI from "./hosting-api.js";
5
+ function check(domain, db) {
6
+ return hostingAPI.check(domain);
7
+ }
8
+ var hosting_default = {
9
+ check
10
+ };
11
+ export {
12
+ hosting_default as default
13
+ };
@@ -1,36 +1,20 @@
1
1
  "use strict";
2
-
3
- const fs = require("fs");
4
- const path = require("path");
5
-
6
- const hosting = require("./hosting");
7
- const pagexray = require("pagexray");
8
-
9
- const jsonPath = path.resolve(
10
- __dirname,
11
- "..",
12
- "data",
13
- "fixtures",
14
- "url2green.test.json"
15
- );
16
-
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import pagexray from "pagexray";
5
+ import hosting from "./hosting-node.js";
6
+ const jsonPath = path.resolve(__dirname, "..", "data", "fixtures", "url2green.test.json");
17
7
  describe("hosting", () => {
18
8
  let har;
19
9
  beforeEach(() => {
20
- har = JSON.parse(
21
- fs.readFileSync(
22
- path.resolve(__dirname, "../data/fixtures/tgwf.har"),
23
- "utf8"
24
- )
25
- );
10
+ har = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../data/fixtures/tgwf.har"), "utf8"));
26
11
  });
27
- describe("checking all domains on a page object with #checkPage ", () => {
28
- it("it returns a list of green domains, when passed a page object", async () => {
12
+ describe("checking all domains on a page object with #checkPage", () => {
13
+ it("returns a list of green domains, when passed a page object", async () => {
29
14
  const pages = pagexray.convert(har);
30
15
  const pageXrayRun = pages[0];
31
16
  const db = await hosting.loadJSON(jsonPath);
32
17
  const greenDomains = await hosting.checkPage(pageXrayRun, db);
33
-
34
18
  expect(greenDomains).toHaveLength(11);
35
19
  const expectedGreendomains = [
36
20
  "maxcdn.bootstrapcdn.com",
@@ -43,15 +27,12 @@ describe("hosting", () => {
43
27
  "graphite.thegreenwebfoundation.org",
44
28
  "analytics.thegreenwebfoundation.org",
45
29
  "fonts.gstatic.com",
46
- "api.thegreenwebfoundation.org",
30
+ "api.thegreenwebfoundation.org"
47
31
  ];
48
- greenDomains.forEach(function (dom) {
32
+ greenDomains.forEach((dom) => {
49
33
  expect(expectedGreendomains).toContain(dom);
50
34
  });
51
35
  });
52
- // it(
53
- // 'it returns an empty list, when passed a page object with no green domains'
54
- // );
55
36
  });
56
37
  describe("checking a single domain with #check", () => {
57
38
  it("use the API instead", async () => {
@@ -63,7 +44,6 @@ describe("hosting", () => {
63
44
  describe("implicitly checking multiple domains with #check", () => {
64
45
  it("Use the API", async () => {
65
46
  const db = await hosting.loadJSON(jsonPath);
66
-
67
47
  const res = await hosting.check(["google.com", "kochindustries.com"], db);
68
48
  expect(res).toContain("google.com");
69
49
  });
@@ -0,0 +1,8 @@
1
+ import co2 from "./co2.js";
2
+ import hosting from "./hosting.js";
3
+ var src_default = { co2, hosting };
4
+ export {
5
+ co2,
6
+ src_default as default,
7
+ hosting
8
+ };
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ import debugFactory from "debug";
3
+ const log = debugFactory("tgwf:sustainable-web-design");
4
+ import { fileSize } from "./constants/index.js";
5
+ import { formatNumber } from "./helpers/index.js";
6
+ const KWH_PER_GB = 0.81;
7
+ const END_USER_DEVICE_ENERGY = 0.52;
8
+ const NETWORK_ENERGY = 0.14;
9
+ const DATACENTER_ENERGY = 0.15;
10
+ const PRODUCTION_ENERGY = 0.19;
11
+ const GLOBAL_INTENSITY = 442;
12
+ const RENEWABLES_INTENSITY = 50;
13
+ const FIRST_TIME_VIEWING_PERCENTAGE = 0.75;
14
+ const RETURNING_VISITOR_PERCENTAGE = 0.25;
15
+ const PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD = 0.02;
16
+ class SustainableWebDesign {
17
+ constructor(options) {
18
+ this.options = options;
19
+ }
20
+ energyPerByteByComponent(bytes) {
21
+ const transferedBytesToGb = bytes / fileSize.GIGABYTE;
22
+ const energyUsage = transferedBytesToGb * KWH_PER_GB;
23
+ return {
24
+ consumerDeviceEnergy: energyUsage * END_USER_DEVICE_ENERGY,
25
+ networkEnergy: energyUsage * NETWORK_ENERGY,
26
+ productionEnergy: energyUsage * PRODUCTION_ENERGY,
27
+ dataCenterEnergy: energyUsage * DATACENTER_ENERGY
28
+ };
29
+ }
30
+ co2byComponent(energyBycomponent, carbonIntensity = GLOBAL_INTENSITY) {
31
+ const returnCO2ByComponent = {};
32
+ for (const [key, value] of Object.entries(energyBycomponent)) {
33
+ if (key === "dataCenterEnergy") {
34
+ returnCO2ByComponent[key] = value * carbonIntensity;
35
+ } else {
36
+ returnCO2ByComponent[key] = value * GLOBAL_INTENSITY;
37
+ }
38
+ }
39
+ return returnCO2ByComponent;
40
+ }
41
+ perByte(bytes, carbonIntensity = GLOBAL_INTENSITY) {
42
+ const energyBycomponent = this.energyPerByteByComponent(bytes);
43
+ if (Boolean(carbonIntensity) === false) {
44
+ carbonIntensity = GLOBAL_INTENSITY;
45
+ }
46
+ if (carbonIntensity === true) {
47
+ carbonIntensity = RENEWABLES_INTENSITY;
48
+ }
49
+ if (typeof carbonIntensity !== "number") {
50
+ throw new Error(`perByte expects a numeric value or boolean for the carbon intensity value. Received: ${carbonIntensity}`);
51
+ }
52
+ const co2ValuesbyComponent = this.co2byComponent(energyBycomponent, carbonIntensity);
53
+ const co2Values = Object.values(co2ValuesbyComponent);
54
+ return co2Values.reduce((prevValue, currentValue) => prevValue + currentValue);
55
+ }
56
+ energyPerByte(bytes) {
57
+ const energyByComponent = this.energyPerByteByComponent(bytes);
58
+ const energyValues = Object.values(energyByComponent);
59
+ return energyValues.reduce((prevValue, currentValue) => prevValue + currentValue);
60
+ }
61
+ energyPerVisitByComponent(bytes, firstView = FIRST_TIME_VIEWING_PERCENTAGE, returnView = RETURNING_VISITOR_PERCENTAGE, dataReloadRatio = PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD) {
62
+ const energyBycomponent = this.energyPerByteByComponent(bytes);
63
+ const cacheAdjustedSegmentEnergy = {};
64
+ log({ energyBycomponent });
65
+ const energyValues = Object.values(energyBycomponent);
66
+ const v9recombinedNoCaching = energyValues.reduce((prevValue, currentValue) => prevValue + currentValue);
67
+ log({ v9recombinedNoCaching });
68
+ for (const [key, value] of Object.entries(energyBycomponent)) {
69
+ cacheAdjustedSegmentEnergy[`${key} - first`] = value * firstView;
70
+ cacheAdjustedSegmentEnergy[`${key} - subsequent`] = value * returnView * dataReloadRatio;
71
+ }
72
+ log({ cacheAdjustedSegmentEnergy });
73
+ return cacheAdjustedSegmentEnergy;
74
+ }
75
+ energyPerVisit(bytes) {
76
+ let v9firstVisits = 0;
77
+ let v9subsequentVisits = 0;
78
+ const energyBycomponent = Object.entries(this.energyPerVisitByComponent(bytes));
79
+ for (const [key, val] of energyBycomponent) {
80
+ if (key.indexOf("first") > 0) {
81
+ v9firstVisits += val;
82
+ }
83
+ }
84
+ for (const [key, val] of energyBycomponent) {
85
+ if (key.indexOf("subsequent") > 0) {
86
+ v9subsequentVisits += val;
87
+ }
88
+ }
89
+ log({ v9firstVisits });
90
+ log({ v9subsequentVisits });
91
+ return v9firstVisits + v9subsequentVisits;
92
+ }
93
+ energyPerVisitV8(bytes) {
94
+ log({ bytes });
95
+ const transferedBytesToGb = bytes / fileSize.GIGABYTE;
96
+ const v8visitWithNoCaching = transferedBytesToGb * KWH_PER_GB;
97
+ const v8firstVisit = transferedBytesToGb * KWH_PER_GB * RETURNING_VISITOR_PERCENTAGE;
98
+ const v8subsequentVisits = transferedBytesToGb * KWH_PER_GB * FIRST_TIME_VIEWING_PERCENTAGE * PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD;
99
+ const v8firstAndSubsequentVisits = v8firstVisit + v8subsequentVisits;
100
+ log({ v8visitWithNoCaching });
101
+ log({ v8firstVisit });
102
+ log({ v8subsequentVisits });
103
+ log({ v8firstAndSubsequentVisits });
104
+ return v8firstVisit + v8subsequentVisits;
105
+ }
106
+ emissionsPerVisitInGrams(energyPerVisit, carbonintensity = GLOBAL_INTENSITY) {
107
+ return formatNumber(energyPerVisit * carbonintensity);
108
+ }
109
+ annualEnergyInKwh(energyPerVisit, monthlyVisitors = 1e3) {
110
+ return energyPerVisit * monthlyVisitors * 12;
111
+ }
112
+ annualEmissionsInGrams(co2grams, monthlyVisitors = 1e3) {
113
+ return co2grams * monthlyVisitors * 12;
114
+ }
115
+ annualSegmentEnergy(annualEnergy) {
116
+ return {
117
+ consumerDeviceEnergy: formatNumber(annualEnergy * END_USER_DEVICE_ENERGY),
118
+ networkEnergy: formatNumber(annualEnergy * NETWORK_ENERGY),
119
+ dataCenterEnergy: formatNumber(annualEnergy * DATACENTER_ENERGY),
120
+ productionEnergy: formatNumber(annualEnergy * PRODUCTION_ENERGY)
121
+ };
122
+ }
123
+ }
124
+ var sustainable_web_design_default = SustainableWebDesign;
125
+ export {
126
+ SustainableWebDesign,
127
+ sustainable_web_design_default as default
128
+ };
@@ -1,80 +1,68 @@
1
- const SustainableWebDesign = require("./sustainable-web-design");
2
-
1
+ import SustainableWebDesign from "./sustainable-web-design.js";
3
2
  describe("sustainable web design model", () => {
4
3
  const swd = new SustainableWebDesign();
5
- const averageWebsiteInBytes = 2257715.2;
6
-
4
+ const averageWebsiteInBytes = 22577152e-1;
7
5
  describe("energyPerByteByComponent", () => {
8
6
  it("should return a object with numbers for each system component", () => {
9
7
  const groupedEnergy = swd.energyPerByteByComponent(averageWebsiteInBytes);
10
-
11
- expect(groupedEnergy.consumerDeviceEnergy).toBeCloseTo(0.00088564, 8);
12
- expect(groupedEnergy.networkEnergy).toBeCloseTo(0.00023844, 8);
13
- expect(groupedEnergy.productionEnergy).toBeCloseTo(0.0003236, 8);
14
- expect(groupedEnergy.dataCenterEnergy).toBeCloseTo(0.00025547, 8);
8
+ expect(groupedEnergy.consumerDeviceEnergy).toBeCloseTo(88564e-8, 8);
9
+ expect(groupedEnergy.networkEnergy).toBeCloseTo(23844e-8, 8);
10
+ expect(groupedEnergy.productionEnergy).toBeCloseTo(3236e-7, 8);
11
+ expect(groupedEnergy.dataCenterEnergy).toBeCloseTo(25547e-8, 8);
15
12
  });
16
13
  });
17
-
18
14
  describe("energyPerByte", () => {
19
15
  it("should return a number in kilowatt hours for the given data transfer in bytes", () => {
20
16
  const energyForTransfer = swd.energyPerByte(averageWebsiteInBytes);
21
- expect(energyForTransfer).toBeCloseTo(0.00170316, 7);
17
+ expect(energyForTransfer).toBeCloseTo(170316e-8, 7);
22
18
  });
23
19
  });
24
-
25
20
  describe("perByte", () => {
26
21
  it("should return a single number for CO2 emissions", () => {
27
- expect(typeof swd.perByte(2257715.2)).toBe("number");
22
+ expect(typeof swd.perByte(22577152e-1)).toBe("number");
28
23
  });
29
24
  });
30
-
31
- describe("energyPerVisit", function () {
25
+ describe("energyPerVisit", () => {
32
26
  it("should return a number", () => {
33
27
  expect(typeof swd.energyPerVisit(averageWebsiteInBytes)).toBe("number");
34
28
  });
35
-
36
29
  it("should calculate the correct energy", () => {
37
- expect(swd.energyPerVisit(averageWebsiteInBytes)).toBe(
38
- 0.0004513362121582032
39
- );
30
+ expect(swd.energyPerVisit(averageWebsiteInBytes)).toBe(0.001285882415771485);
31
+ });
32
+ it("should match the old calculations", () => {
33
+ const v9currentEnergyCalc = swd.energyPerVisit(averageWebsiteInBytes);
34
+ const v8VersionEnergyCalc = swd.energyPerVisitV8(averageWebsiteInBytes);
35
+ expect(swd.emissionsPerVisitInGrams(v9currentEnergyCalc)).toEqual(0.57);
36
+ expect(swd.emissionsPerVisitInGrams(v8VersionEnergyCalc)).toEqual(0.2);
40
37
  });
41
38
  });
42
-
43
- describe("emissionsPerVisitInGrams", function () {
39
+ describe("emissionsPerVisitInGrams", () => {
44
40
  it("should calculate the correct co2 per visit", () => {
45
- const averageWebsiteInBytes = 2257715.2;
46
41
  const energy = swd.energyPerVisit(averageWebsiteInBytes);
47
- expect(swd.emissionsPerVisitInGrams(energy)).toEqual(0.2);
42
+ expect(swd.emissionsPerVisitInGrams(energy)).toEqual(0.57);
48
43
  });
49
-
50
44
  it("should accept a dynamic KwH value", () => {
51
- const averageWebsiteInBytes = 2257715.2;
52
45
  const energy = swd.energyPerVisit(averageWebsiteInBytes);
53
- expect(swd.emissionsPerVisitInGrams(energy, 245)).toEqual(0.11);
46
+ expect(swd.emissionsPerVisitInGrams(energy, 245)).toEqual(0.32);
54
47
  });
55
48
  });
56
-
57
- describe("annualEnergyInKwh", function () {
49
+ describe("annualEnergyInKwh", () => {
58
50
  it("should calculate the correct energy in kWh", () => {
59
51
  expect(swd.annualEnergyInKwh(averageWebsiteInBytes)).toBe(27092582400);
60
52
  });
61
53
  });
62
-
63
- describe("annualEmissionsInGrams", function () {
54
+ describe("annualEmissionsInGrams", () => {
64
55
  it("should calculate the corrent energy in grams", () => {
65
- expect(swd.annualEmissionsInGrams(averageWebsiteInBytes)).toBe(
66
- 27092582400
67
- );
56
+ expect(swd.annualEmissionsInGrams(averageWebsiteInBytes)).toBe(27092582400);
68
57
  });
69
58
  });
70
-
71
- describe("annualSegmentEnergy", function () {
59
+ describe("annualSegmentEnergy", () => {
72
60
  it("should return the correct values", () => {
73
61
  expect(swd.annualSegmentEnergy(averageWebsiteInBytes)).toEqual({
74
- consumerDeviceEnergy: 1174011.9,
62
+ consumerDeviceEnergy: 11740119e-1,
75
63
  dataCenterEnergy: 338657.28,
76
64
  networkEnergy: 316080.13,
77
- productionEnergy: 428965.89,
65
+ productionEnergy: 428965.89
78
66
  });
79
67
  });
80
68
  });
package/fixup ADDED
@@ -0,0 +1,19 @@
1
+ #!/bin/bash
2
+ #
3
+ # Add package.json files to cjs/esm subtrees in dist
4
+ # This is needed to allow one package to work with
5
+ # commonJS for older node versions, and for using ES6 imports
6
+ # for browsers, and newer versions of node
7
+ #
8
+
9
+ cat >dist/cjs/package.json <<!EOF
10
+ {
11
+ "type": "commonjs"
12
+ }
13
+ !EOF
14
+
15
+ cat >dist/esm/package.json <<!EOF
16
+ {
17
+ "type": "module"
18
+ }
19
+ !EOF
package/package.json CHANGED
@@ -1,14 +1,26 @@
1
1
  {
2
2
  "name": "@tgwf/co2",
3
- "version": "0.9.0-0",
3
+ "version": "0.10.1",
4
4
  "description": "Work out the co2 of your digital services",
5
- "main": "src/index.js",
5
+ "main": "dist/cjs/index-node.js",
6
+ "module": "dist/esm/index.js",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/esm/index.js",
10
+ "require": "./dist/cjs/index-node.js"
11
+ }
12
+ },
6
13
  "scripts": {
7
- "test": "jest",
8
- "test:watch": "jest --watch",
9
- "lint": "eslint .",
10
- "lint:fix": "eslint . --fix",
11
- "travis": "npm run lint && jest"
14
+ "test": "jest src",
15
+ "test:watch": "jest --watch src",
16
+ "lint": "eslint src",
17
+ "lint:fix": "eslint src --fix",
18
+ "serve": "python -m http.server --directory ./public",
19
+ "build": "npm run build:esm && npm run build:browser && npm run build:node",
20
+ "build:esm": "node .esbuild.esm.js && ./fixup",
21
+ "build:browser": "node .esbuild.browser.js",
22
+ "build:node": "node .esbuild.node.js && ./fixup",
23
+ "gitpod": "npm run build && cp ./dist/iife/index.js ./public && npm run serve"
12
24
  },
13
25
  "keywords": [
14
26
  "sustainability",
@@ -23,16 +35,25 @@
23
35
  "license": "Apache-2.0",
24
36
  "devDependencies": {
25
37
  "@tgwf/url2green": "^0.4.0",
26
- "eslint": "^8.3.0",
27
- "eslint-config-prettier": "^8.3.0",
28
- "eslint-plugin-jest": "^25.2.4",
38
+ "eslint": "^8.15.0",
39
+ "eslint-config-prettier": "^8.5.0",
40
+ "eslint-plugin-jest": "^26.1.5",
29
41
  "eslint-plugin-prettier": "^4.0.0",
30
- "jest": "^27.3.1",
31
- "minimist": "^1.2.5",
32
- "nock": "^13.2.1",
33
- "np": "^7.6.0",
34
- "pagexray": "^4.3.1",
35
- "prettier": "^2.4.1"
42
+ "esbuild": "^0.14.47",
43
+ "esbuild-jest": "^0.5.0",
44
+ "esbuild-plugin-glob": "^1.1.2",
45
+ "jest": "^28.1.0",
46
+ "nock": "^13.2.4",
47
+ "np": "^7.6.1",
48
+ "pagexray": "^4.4.2",
49
+ "prettier": "^2.6.2"
50
+ },
51
+ "jest": {
52
+ "transform": {
53
+ "^.+\\.(t|j)sx?$": [
54
+ "esbuild-jest"
55
+ ]
56
+ }
36
57
  },
37
58
  "np": {
38
59
  "yarn": false
@@ -41,7 +62,7 @@
41
62
  "access": "public"
42
63
  },
43
64
  "dependencies": {
44
- "debug": "^4.1.1"
65
+ "debug": "^4.3.4"
45
66
  },
46
67
  "repository": {
47
68
  "type": "git",
@@ -0,0 +1,58 @@
1
+ <html>
2
+
3
+ <head>
4
+ <meta charset=utf-8>
5
+ </head>
6
+
7
+
8
+ <body class="">
9
+
10
+ <h1>This is a minimal demo using the IIFE version of CO2.js.</h1>
11
+
12
+ <p>Add a number in bytes, and we convert it to carbon, using the SWD model</p>
13
+
14
+ <form>
15
+ <p>
16
+ <label for="bytes">Number of bytes</label>
17
+ <input name="bytes" value=0 />
18
+ </p>
19
+ <button>Update</button>
20
+ </form>
21
+
22
+ <h2 class="result">
23
+ (result goes here)
24
+ </h2>
25
+
26
+
27
+ <script src="./index.js"></script>
28
+ <script>
29
+ let emissions = new co2.co2();
30
+
31
+ async function main() {
32
+
33
+ // this is included to demonstrate checking a given domain
34
+ const hosting = co2.hosting
35
+ // is the result green?
36
+ const result = await hosting.check("google.com")
37
+ // should return true or false
38
+ console.log({
39
+ result
40
+ })
41
+
42
+ document.querySelector('form').addEventListener('submit', function (event) {
43
+ event.preventDefault();
44
+ event.stopPropagation();
45
+
46
+ const thisForm = event.target
47
+ const bytes = thisForm.querySelector('input').value
48
+ const result = emissions.perByte(bytes)
49
+
50
+ document.querySelector('.result').textContent = result
51
+ document.querySelector('body').classList = []
52
+ })
53
+ }
54
+ main()
55
+ </script>
56
+ </body>
57
+
58
+ </html>
@@ -0,0 +1,2 @@
1
+ var co2=(()=>{var V=Object.create;var b=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var ee=Object.getPrototypeOf,te=Object.prototype.hasOwnProperty;var v=(r,t)=>()=>(t||r((t={exports:{}}).exports,t),t.exports),re=(r,t)=>{for(var e in t)b(r,e,{get:t[e],enumerable:!0})},z=(r,t,e,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of X(t))!te.call(r,n)&&n!==e&&b(r,n,{get:()=>t[n],enumerable:!(o=Q(t,n))||o.enumerable});return r};var D=(r,t,e)=>(e=r!=null?V(ee(r)):{},z(t||!r||!r.__esModule?b(e,"default",{value:r,enumerable:!0}):e,r)),ne=r=>z(b({},"__esModule",{value:!0}),r);var G=v((ve,H)=>{var m=1e3,g=m*60,y=g*60,p=y*24,oe=p*7,se=p*365.25;H.exports=function(r,t){t=t||{};var e=typeof r;if(e==="string"&&r.length>0)return ie(r);if(e==="number"&&isFinite(r))return t.long?ae(r):ce(r);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(r))};function ie(r){if(r=String(r),!(r.length>100)){var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(r);if(!!t){var e=parseFloat(t[1]),o=(t[2]||"ms").toLowerCase();switch(o){case"years":case"year":case"yrs":case"yr":case"y":return e*se;case"weeks":case"week":case"w":return e*oe;case"days":case"day":case"d":return e*p;case"hours":case"hour":case"hrs":case"hr":case"h":return e*y;case"minutes":case"minute":case"mins":case"min":case"m":return e*g;case"seconds":case"second":case"secs":case"sec":case"s":return e*m;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return e;default:return}}}}function ce(r){var t=Math.abs(r);return t>=p?Math.round(r/p)+"d":t>=y?Math.round(r/y)+"h":t>=g?Math.round(r/g)+"m":t>=m?Math.round(r/m)+"s":r+"ms"}function ae(r){var t=Math.abs(r);return t>=p?R(r,t,p,"day"):t>=y?R(r,t,y,"hour"):t>=g?R(r,t,g,"minute"):t>=m?R(r,t,m,"second"):r+" ms"}function R(r,t,e,o){var n=t>=e*1.5;return Math.round(r/e)+" "+o+(n?"s":"")}});var Y=v((Pe,M)=>{function ue(r){e.debug=e,e.default=e,e.coerce=x,e.disable=i,e.enable=n,e.enabled=u,e.humanize=G(),e.destroy=F,Object.keys(r).forEach(s=>{e[s]=r[s]}),e.names=[],e.skips=[],e.formatters={};function t(s){let c=0;for(let a=0;a<s.length;a++)c=(c<<5)-c+s.charCodeAt(a),c|=0;return e.colors[Math.abs(c)%e.colors.length]}e.selectColor=t;function e(s){let c,a=null,_,T;function C(...l){if(!C.enabled)return;let h=C,E=Number(new Date),q=E-(c||E);h.diff=q,h.prev=c,h.curr=E,c=E,l[0]=e.coerce(l[0]),typeof l[0]!="string"&&l.unshift("%O");let w=0;l[0]=l[0].replace(/%([a-zA-Z%])/g,(I,J)=>{if(I==="%%")return"%";w++;let B=e.formatters[J];if(typeof B=="function"){let Z=l[w];I=B.call(h,Z),l.splice(w,1),w--}return I}),e.formatArgs.call(h,l),(h.log||e.log).apply(h,l)}return C.namespace=s,C.useColors=e.useColors(),C.color=e.selectColor(s),C.extend=o,C.destroy=e.destroy,Object.defineProperty(C,"enabled",{enumerable:!0,configurable:!1,get:()=>a!==null?a:(_!==e.namespaces&&(_=e.namespaces,T=e.enabled(s)),T),set:l=>{a=l}}),typeof e.init=="function"&&e.init(C),C}function o(s,c){let a=e(this.namespace+(typeof c>"u"?":":c)+s);return a.log=this.log,a}function n(s){e.save(s),e.namespaces=s,e.names=[],e.skips=[];let c,a=(typeof s=="string"?s:"").split(/[\s,]+/),_=a.length;for(c=0;c<_;c++)!a[c]||(s=a[c].replace(/\*/g,".*?"),s[0]==="-"?e.skips.push(new RegExp("^"+s.slice(1)+"$")):e.names.push(new RegExp("^"+s+"$")))}function i(){let s=[...e.names.map(d),...e.skips.map(d).map(c=>"-"+c)].join(",");return e.enable(""),s}function u(s){if(s[s.length-1]==="*")return!0;let c,a;for(c=0,a=e.skips.length;c<a;c++)if(e.skips[c].test(s))return!1;for(c=0,a=e.names.length;c<a;c++)if(e.names[c].test(s))return!0;return!1}function d(s){return s.toString().substring(2,s.toString().length-2).replace(/\.\*\?$/,"*")}function x(s){return s instanceof Error?s.stack||s.message:s}function F(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}return e.enable(e.load()),e}M.exports=ue});var N=v((f,O)=>{f.formatArgs=le;f.save=Ce;f.load=de;f.useColors=fe;f.storage=he();f.destroy=(()=>{let r=!1;return()=>{r||(r=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})();f.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function fe(){return typeof window<"u"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs)?!0:typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)?!1:typeof document<"u"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<"u"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function le(r){if(r[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+r[0]+(this.useColors?"%c ":" ")+"+"+O.exports.humanize(this.diff),!this.useColors)return;let t="color: "+this.color;r.splice(1,0,t,"color: inherit");let e=0,o=0;r[0].replace(/%[a-zA-Z%]/g,n=>{n!=="%%"&&(e++,n==="%c"&&(o=e))}),r.splice(o,0,t)}f.log=console.debug||console.log||(()=>{});function Ce(r){try{r?f.storage.setItem("debug",r):f.storage.removeItem("debug")}catch{}}function de(){let r;try{r=f.storage.getItem("debug")}catch{}return!r&&typeof process<"u"&&"env"in process&&(r=process.env.DEBUG),r}function he(){try{return localStorage}catch{}}O.exports=Y()(f);var{formatters:pe}=O.exports;pe.j=function(r){try{return JSON.stringify(r)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}}});var we={};re(we,{co2:()=>W,default:()=>Ee,hosting:()=>K});var P=4883333333333333e-25;var k=class{constructor(t){this.options=t,this.KWH_PER_BYTE_FOR_NETWORK=P}perByte(t,e){if(t<1)return 0;if(e){let n=t*72e-12*0,i=t*P*475;return n+i}let o=72e-12+P;return t*o*519}};var j=k;var S=class{constructor(t){this.options=t,this.model=new j,t&&(this.model=new t.model)}perByte(t,e){return this.model.perByte(t,e)}perDomain(t,e){let o=[];for(let n of Object.keys(t.domains)){let i;e&&e.indexOf(n)>-1?i=this.perByte(t.domains[n].transferSize,!0):i=this.perByte(t.domains[n].transferSize),o.push({domain:n,co2:i,transferSize:t.domains[n].transferSize})}return o.sort((n,i)=>i.co2-n.co2),o}perPage(t,e){let o=this.perDomain(t,e),n=0;for(let i of o)n+=i.co2;return n}perContentType(t,e){let o={};for(let i of t.assets){let u=new URL(i.url).domain,d=i.transferSize,x=this.perByte(d,e&&e.indexOf(u)>-1),F=i.type;o[F]||(o[F]={co2:0,transferSize:0}),o[F].co2+=x,o[F].transferSize+=d}let n=[];for(let i of Object.keys(o))n.push({type:i,co2:o[i].co2,transferSize:o[i].transferSize});return n.sort((i,u)=>u.co2-i.co2),n}dirtiestResources(t,e){let o=[];for(let n of t.assets){let i=new URL(n.url).domain,u=n.transferSize,d=this.perByte(u,e&&e.indexOf(i)>-1);o.push({url:n.url,co2:d,transferSize:u})}return o.sort((n,i)=>i.co2-n.co2),o.slice(0,o.length>10?10:o.length)}perParty(t,e){let o=0,n=0,i=t.firstPartyRegEx;for(let u of Object.keys(t.domains))u.match(i)?o+=this.perByte(t.domains[u].transferSize,e&&e.indexOf(u)>-1):n+=this.perByte(t.domains[u].transferSize,e&&e.indexOf(u)>-1);return{firstParty:o,thirdParty:n}}};var W=S;var U=D(N());var $=D(N()),A=(0,$.default)("tgwf:hostingAPI");function Fe(r){return typeof r=="string"?me(r):ge(r)}async function me(r){return(await(await fetch(`https://api.thegreenwebfoundation.org/greencheck/${r}`)).json()).green}async function ge(r){try{let t="https://api.thegreenwebfoundation.org/v2/greencheckmulti",e=JSON.stringify(r),o=await fetch(`${t}/${e}`);A(`${t}/${e}`),A({req:o});let n=await o.text();A({textResult:n});let i=await o.json();return ye(i)}catch{return[]}}function ye(r){return Object.entries(r).filter(([o,n])=>n.green).map(([o,n])=>n.url)}var L={check:Fe};var Se=(0,U.default)("tgwf:hosting");function _e(r,t){return L.check(r)}var K={check:_e};var Ee={co2:W,hosting:K};return ne(we);})();
2
+ //# sourceMappingURL=index.js.map