@tgwf/co2 0.9.0 → 0.10.0

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/.tool-versions +1 -0
  5. package/CHANGELOG.md +13 -2
  6. package/README.md +6 -8
  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 +37 -17
  65. package/public/index.html +57 -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 +1 -1
  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 +79 -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
@@ -0,0 +1,11 @@
1
+ require('esbuild').buildSync({
2
+ entryPoints: ['src/index.js'],
3
+ outdir: 'public',
4
+ globalName: 'co2',
5
+ format: 'iife',
6
+ platform: 'browser',
7
+ bundle: true,
8
+ sourcemap: true,
9
+ minify: true,
10
+ // target: ['es5'],
11
+ })
@@ -0,0 +1,25 @@
1
+ const esbuild = require('esbuild')
2
+ // tiny glob is a dependency of `esbuild-plugin-glob`.
3
+ // For this build however we need to filter out some extra files
4
+ // that are used for nodejs, but not in browsers, so we use the
5
+ // library directly instead of using `esbuild-plugin-glob` as a plugin
6
+ const glob = require('tiny-glob');
7
+
8
+ async function main() {
9
+ const results = await glob('src/**/**.js')
10
+ // we remove node specific files here, with the assumption that
11
+ // the common use case is bundling into browser based web apps
12
+ const justBrowserCompatibleFiles = results.filter(filepath => !filepath.endsWith('node.js'))
13
+
14
+ esbuild.build({
15
+ entryPoints: justBrowserCompatibleFiles,
16
+ bundle: false,
17
+ minify: false,
18
+ sourcemap: false,
19
+ target: ['chrome58', 'firefox57', 'safari11', 'edge18', 'esnext'],
20
+ outdir: 'dist/esm',
21
+ outExtension: { '.js': '.js' },
22
+ format: 'esm'
23
+ })
24
+ }
25
+ main()
@@ -0,0 +1,16 @@
1
+ const { globPlugin } = require('esbuild-plugin-glob');
2
+
3
+ function main() {
4
+ require('esbuild').build({
5
+ entryPoints: ['src/**/**.js',],
6
+ bundle: false,
7
+ minify: false,
8
+ sourcemap: true,
9
+ target: ['node14'],
10
+ outdir: 'dist/cjs/',
11
+ outExtension: { '.js': '.js' },
12
+ format: 'cjs',
13
+ plugins: [globPlugin()]
14
+ })
15
+ }
16
+ main()
package/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ nodejs 18.4.0
package/CHANGELOG.md CHANGED
@@ -4,10 +4,21 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
- -
8
7
 
9
- ## Unreleased
8
+ > **Added** for new features.
9
+ > **Changed** for changes in existing functionality.
10
+ > **Deprecated** for soon-to-be removed features.
11
+ > **Removed** for now removed features.
12
+ > **Fixed** for any bug fixes.
13
+ > **Security** in case of vulnerabilities.
10
14
 
15
+ ## 0.10.0 2022-06-27
16
+
17
+ - Added ES import syntax as the main way for handling imports and exports of code within the module.
18
+ - Changed eslint settings to use later version of ecmascript (2020)
19
+ - Change the bulid tools to use esbulid with jest instead of babel
20
+ - Added more consistent use of the debug logging library in files using the updated import syntax
21
+ - Fixed the incorrect order of FIRST_TIME_VIEWING_PERCENTAGE and RETURNING_VISITOR_PERCENTAGE constants in the SWD model. This will result in **larger** values for calculations using the sustainable web design, and the default caching assumptions.
11
22
 
12
23
 
13
24
  # [0.9.0] - 2022-03-28
package/README.md CHANGED
@@ -57,13 +57,13 @@ console.log(`Sending a gigabyte, had a carbon footprint of ${estimatedCO2.toFixe
57
57
 
58
58
  #### Browser-side
59
59
 
60
- For browser-based solutions, you must import the `co2.js` submodule directly from `node_modules`. For example, like this:
60
+ For example, like this:
61
61
 
62
62
  ```js
63
63
 
64
- const CO2 = require('node_modules/@tgwf/co2/src/co2.js')
64
+ import { co2 } from '@tgwf/co2'
65
65
  const bytesSent = (1024 * 1024 * 1024)
66
- const co2Emission = new CO2();
66
+ const co2Emission = new co2();
67
67
  estimatedCO2 = co2Emission.perByte(bytesSent)
68
68
 
69
69
  console.log(`Sending a gigabyte, had a carbon footprint of ${estimatedCO2.toFixed(3)} grams of CO2`)
@@ -76,16 +76,14 @@ Because different digital services and websites use different forms of power, th
76
76
 
77
77
  ```js
78
78
 
79
- const greencheck = require('@tgwf/hosting')
79
+ import { hosting } from '@tgwf/co2'
80
80
 
81
81
  // returns true if green, otherwise false
82
- greencheck.check("google.com")
82
+ hosting.check("google.com")
83
83
 
84
84
  // returns an array of the green domains, in this case ["google.com"].
85
- greencheck.check(["google.com", "kochindustries.com"])]
85
+ hosting.check(["google.com", "kochindustries.com"])]
86
86
 
87
- // returns an array of green domains, again in this case, ["google.com"]
88
- greencheck.checkPage(["google.com"])
89
87
 
90
88
  ```
91
89
 
@@ -0,0 +1,52 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var byte_exports = {};
19
+ __export(byte_exports, {
20
+ OneByte: () => OneByte,
21
+ default: () => byte_default
22
+ });
23
+ module.exports = __toCommonJS(byte_exports);
24
+ const CO2_PER_KWH_IN_DC_GREY = 519;
25
+ const CO2_PER_KWH_NETWORK_GREY = 475;
26
+ const CO2_PER_KWH_IN_DC_GREEN = 0;
27
+ const KWH_PER_BYTE_IN_DC = 72e-12;
28
+ const FIXED_NETWORK_WIRED = 429e-12;
29
+ const FIXED_NETWORK_WIFI = 152e-12;
30
+ const FOUR_G_MOBILE = 884e-12;
31
+ const KWH_PER_BYTE_FOR_NETWORK = (FIXED_NETWORK_WIRED + FIXED_NETWORK_WIFI + FOUR_G_MOBILE) / 3;
32
+ const KWH_PER_BYTE_FOR_DEVICES = 13e-11;
33
+ class OneByte {
34
+ constructor(options) {
35
+ this.options = options;
36
+ this.KWH_PER_BYTE_FOR_NETWORK = KWH_PER_BYTE_FOR_NETWORK;
37
+ }
38
+ perByte(bytes, green) {
39
+ if (bytes < 1) {
40
+ return 0;
41
+ }
42
+ if (green) {
43
+ const Co2ForDC = bytes * KWH_PER_BYTE_IN_DC * CO2_PER_KWH_IN_DC_GREEN;
44
+ const Co2forNetwork = bytes * KWH_PER_BYTE_FOR_NETWORK * CO2_PER_KWH_NETWORK_GREY;
45
+ return Co2ForDC + Co2forNetwork;
46
+ }
47
+ const KwHPerByte = KWH_PER_BYTE_IN_DC + KWH_PER_BYTE_FOR_NETWORK;
48
+ return bytes * KwHPerByte * CO2_PER_KWH_IN_DC_GREY;
49
+ }
50
+ }
51
+ var byte_default = OneByte;
52
+ //# sourceMappingURL=1byte.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/1byte.js"],
4
+ "sourcesContent": ["// Use the 1byte model for now from the Shift Project, and assume a US grid mix figure they use of around 519 g co2 for the time being. It's lower for Europe, and in particular, France, but for v1, we don't include this\nconst CO2_PER_KWH_IN_DC_GREY = 519;\n\n// this figure is from the IEA's 2018 report for a global average:\nconst CO2_PER_KWH_NETWORK_GREY = 475;\n\n// TODO - these figures need to be updated, as the figures for green\n// shouldn't really be zero now we know that carbon intensity figures\n// for renewables still usually include the life cycle emissions\nconst CO2_PER_KWH_IN_DC_GREEN = 0;\n\n// the 1 byte model gives figures for energy usage for:\n\n// datacentres\n// networks\n// the device used to access a site/app\n\n// The device usage figure combines figures for:\n// 1. the usage for devices (which is small proportion of the energy use)\n// 2. the *making* the device, which is comparatively high.\n\nconst KWH_PER_BYTE_IN_DC = 7.2e-11;\n\n// this is probably best left as something users can define, or\n// a weighted average based on total usage.\n// Using a simple mean for now, as while web traffic to end users might trend\n// towards wifi and mobile,\n// Web traffic between servers is likely wired networks\n\nconst FIXED_NETWORK_WIRED = 4.29e-10;\nconst FIXED_NETWORK_WIFI = 1.52e-10;\nconst FOUR_G_MOBILE = 8.84e-10;\n\n// Pull requests gratefully accepted\nconst KWH_PER_BYTE_FOR_NETWORK =\n (FIXED_NETWORK_WIRED + FIXED_NETWORK_WIFI + FOUR_G_MOBILE) / 3;\n\nconst KWH_PER_BYTE_FOR_DEVICES = 1.3e-10;\n\nclass OneByte {\n constructor(options) {\n this.options = options;\n\n this.KWH_PER_BYTE_FOR_NETWORK = KWH_PER_BYTE_FOR_NETWORK;\n }\n\n perByte(bytes, green) {\n if (bytes < 1) {\n return 0;\n }\n\n if (green) {\n // if we have a green datacentre, use the lower figure for renewable energy\n const Co2ForDC = bytes * KWH_PER_BYTE_IN_DC * CO2_PER_KWH_IN_DC_GREEN;\n\n // but for the worest of the internet, we can't easily check, so assume\n // grey for now\n const Co2forNetwork =\n bytes * KWH_PER_BYTE_FOR_NETWORK * CO2_PER_KWH_NETWORK_GREY;\n\n return Co2ForDC + Co2forNetwork;\n }\n\n const KwHPerByte = KWH_PER_BYTE_IN_DC + KWH_PER_BYTE_FOR_NETWORK;\n return bytes * KwHPerByte * CO2_PER_KWH_IN_DC_GREY;\n }\n}\n\nexport { OneByte };\nexport default OneByte;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,MAAM,yBAAyB;AAG/B,MAAM,2BAA2B;AAKjC,MAAM,0BAA0B;AAYhC,MAAM,qBAAqB;AAQ3B,MAAM,sBAAsB;AAC5B,MAAM,qBAAqB;AAC3B,MAAM,gBAAgB;AAGtB,MAAM,2BACH,uBAAsB,qBAAqB,iBAAiB;AAE/D,MAAM,2BAA2B;AAEjC,MAAM,QAAQ;AAAA,EACZ,YAAY,SAAS;AACnB,SAAK,UAAU;AAEf,SAAK,2BAA2B;AAAA,EAClC;AAAA,EAEA,QAAQ,OAAO,OAAO;AACpB,QAAI,QAAQ,GAAG;AACb,aAAO;AAAA,IACT;AAEA,QAAI,OAAO;AAET,YAAM,WAAW,QAAQ,qBAAqB;AAI9C,YAAM,gBACJ,QAAQ,2BAA2B;AAErC,aAAO,WAAW;AAAA,IACpB;AAEA,UAAM,aAAa,qBAAqB;AACxC,WAAO,QAAQ,aAAa;AAAA,EAC9B;AACF;AAGA,IAAO,eAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
17
+ var import_byte = __toESM(require("./1byte.js"));
18
+ describe("onebyte", () => {
19
+ describe("perByte", () => {
20
+ it("returns a simple average of the different networks", () => {
21
+ const expected_val = 488e-12 .toFixed(12);
22
+ const instance = new import_byte.default();
23
+ expect(instance.KWH_PER_BYTE_FOR_NETWORK.toFixed(12)).toBe(expected_val);
24
+ });
25
+ });
26
+ });
27
+ //# sourceMappingURL=1byte.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/1byte.test.js"],
4
+ "sourcesContent": ["\"use strict\";\n\nimport OneByte from \"./1byte.js\";\n\ndescribe(\"onebyte\", () => {\n describe(\"perByte\", () => {\n it(\"returns a simple average of the different networks\", () => {\n // we limit this to 12 figures with toFixed(12), because\n // we have a recurring 333333 afterwards\n // 4.88e-10 is the same as 0.000000000488\n const expected_val = (0.000000000488).toFixed(12);\n const instance = new OneByte();\n\n expect(instance.KWH_PER_BYTE_FOR_NETWORK.toFixed(12)).toBe(expected_val);\n });\n });\n});\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;AAEA,kBAAoB;AAEpB,SAAS,WAAW,MAAM;AACxB,WAAS,WAAW,MAAM;AACxB,OAAG,sDAAsD,MAAM;AAI7D,YAAM,eAAgB,SAAgB,QAAQ,EAAE;AAChD,YAAM,WAAW,IAAI,oBAAQ;AAE7B,aAAO,SAAS,yBAAyB,QAAQ,EAAE,CAAC,EAAE,KAAK,YAAY;AAAA,IACzE,CAAC;AAAA,EACH,CAAC;AACH,CAAC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
21
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
+ var co2_exports = {};
23
+ __export(co2_exports, {
24
+ CO2: () => CO2,
25
+ default: () => co2_default
26
+ });
27
+ module.exports = __toCommonJS(co2_exports);
28
+ var import_byte = __toESM(require("./1byte.js"));
29
+ class CO2 {
30
+ constructor(options) {
31
+ this.options = options;
32
+ this.model = new import_byte.default();
33
+ if (options) {
34
+ this.model = new options.model();
35
+ }
36
+ }
37
+ perByte(bytes, green) {
38
+ return this.model.perByte(bytes, green);
39
+ }
40
+ perDomain(pageXray, greenDomains) {
41
+ const co2PerDomain = [];
42
+ for (let domain of Object.keys(pageXray.domains)) {
43
+ let co2;
44
+ if (greenDomains && greenDomains.indexOf(domain) > -1) {
45
+ co2 = this.perByte(pageXray.domains[domain].transferSize, true);
46
+ } else {
47
+ co2 = this.perByte(pageXray.domains[domain].transferSize);
48
+ }
49
+ co2PerDomain.push({
50
+ domain,
51
+ co2,
52
+ transferSize: pageXray.domains[domain].transferSize
53
+ });
54
+ }
55
+ co2PerDomain.sort((a, b) => b.co2 - a.co2);
56
+ return co2PerDomain;
57
+ }
58
+ perPage(pageXray, green) {
59
+ const domainCO2 = this.perDomain(pageXray, green);
60
+ let totalCO2 = 0;
61
+ for (let domain of domainCO2) {
62
+ totalCO2 += domain.co2;
63
+ }
64
+ return totalCO2;
65
+ }
66
+ perContentType(pageXray, greenDomains) {
67
+ const co2PerContentType = {};
68
+ for (let asset of pageXray.assets) {
69
+ const domain = new URL(asset.url).domain;
70
+ const transferSize = asset.transferSize;
71
+ const co2ForTransfer = this.perByte(transferSize, greenDomains && greenDomains.indexOf(domain) > -1);
72
+ const contentType = asset.type;
73
+ if (!co2PerContentType[contentType]) {
74
+ co2PerContentType[contentType] = { co2: 0, transferSize: 0 };
75
+ }
76
+ co2PerContentType[contentType].co2 += co2ForTransfer;
77
+ co2PerContentType[contentType].transferSize += transferSize;
78
+ }
79
+ const all = [];
80
+ for (let type of Object.keys(co2PerContentType)) {
81
+ all.push({
82
+ type,
83
+ co2: co2PerContentType[type].co2,
84
+ transferSize: co2PerContentType[type].transferSize
85
+ });
86
+ }
87
+ all.sort((a, b) => b.co2 - a.co2);
88
+ return all;
89
+ }
90
+ dirtiestResources(pageXray, greenDomains) {
91
+ const allAssets = [];
92
+ for (let asset of pageXray.assets) {
93
+ const domain = new URL(asset.url).domain;
94
+ const transferSize = asset.transferSize;
95
+ const co2ForTransfer = this.perByte(transferSize, greenDomains && greenDomains.indexOf(domain) > -1);
96
+ allAssets.push({ url: asset.url, co2: co2ForTransfer, transferSize });
97
+ }
98
+ allAssets.sort((a, b) => b.co2 - a.co2);
99
+ return allAssets.slice(0, allAssets.length > 10 ? 10 : allAssets.length);
100
+ }
101
+ perParty(pageXray, greenDomains) {
102
+ let firstParty = 0;
103
+ let thirdParty = 0;
104
+ const firstPartyRegEx = pageXray.firstPartyRegEx;
105
+ for (let d of Object.keys(pageXray.domains)) {
106
+ if (!d.match(firstPartyRegEx)) {
107
+ thirdParty += this.perByte(pageXray.domains[d].transferSize, greenDomains && greenDomains.indexOf(d) > -1);
108
+ } else {
109
+ firstParty += this.perByte(pageXray.domains[d].transferSize, greenDomains && greenDomains.indexOf(d) > -1);
110
+ }
111
+ }
112
+ return { firstParty, thirdParty };
113
+ }
114
+ }
115
+ var co2_default = CO2;
116
+ //# sourceMappingURL=co2.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/co2.js"],
4
+ "sourcesContent": ["\"use strict\";\n\nimport OneByte from \"./1byte.js\";\n\nclass CO2 {\n constructor(options) {\n this.options = options;\n\n // default model\n this.model = new OneByte();\n\n if (options) {\n this.model = new options.model();\n }\n }\n\n /**\n * Accept a figure in bytes for data transfer, and a boolean for whether\n * the domain shows as 'green', and return a CO2 figure for energy used to shift the corresponding\n * the data transfer.\n *\n * @param {number} bytes\n * @param {boolean} green\n * @return {number} the amount of CO2 in grammes\n */\n perByte(bytes, green) {\n return this.model.perByte(bytes, green);\n }\n\n perDomain(pageXray, greenDomains) {\n const co2PerDomain = [];\n for (let domain of Object.keys(pageXray.domains)) {\n let co2;\n if (greenDomains && greenDomains.indexOf(domain) > -1) {\n co2 = this.perByte(pageXray.domains[domain].transferSize, true);\n } else {\n co2 = this.perByte(pageXray.domains[domain].transferSize);\n }\n co2PerDomain.push({\n domain,\n co2,\n transferSize: pageXray.domains[domain].transferSize,\n });\n }\n co2PerDomain.sort((a, b) => b.co2 - a.co2);\n\n return co2PerDomain;\n }\n\n perPage(pageXray, green) {\n // Accept an xray object, and if we receive a boolean as the second\n // argument, we assume every request we make is sent to a server\n // running on renwewable power.\n\n // if we receive an array of domains, return a number accounting the\n // reduced CO2 from green hosted domains\n\n const domainCO2 = this.perDomain(pageXray, green);\n let totalCO2 = 0;\n for (let domain of domainCO2) {\n totalCO2 += domain.co2;\n }\n return totalCO2;\n }\n\n perContentType(pageXray, greenDomains) {\n const co2PerContentType = {};\n for (let asset of pageXray.assets) {\n const domain = new URL(asset.url).domain;\n const transferSize = asset.transferSize;\n const co2ForTransfer = this.perByte(\n transferSize,\n greenDomains && greenDomains.indexOf(domain) > -1\n );\n const contentType = asset.type;\n if (!co2PerContentType[contentType]) {\n co2PerContentType[contentType] = { co2: 0, transferSize: 0 };\n }\n co2PerContentType[contentType].co2 += co2ForTransfer;\n co2PerContentType[contentType].transferSize += transferSize;\n }\n // restructure and sort\n const all = [];\n for (let type of Object.keys(co2PerContentType)) {\n all.push({\n type,\n co2: co2PerContentType[type].co2,\n transferSize: co2PerContentType[type].transferSize,\n });\n }\n all.sort((a, b) => b.co2 - a.co2);\n return all;\n }\n\n dirtiestResources(pageXray, greenDomains) {\n const allAssets = [];\n for (let asset of pageXray.assets) {\n const domain = new URL(asset.url).domain;\n const transferSize = asset.transferSize;\n const co2ForTransfer = this.perByte(\n transferSize,\n greenDomains && greenDomains.indexOf(domain) > -1\n );\n allAssets.push({ url: asset.url, co2: co2ForTransfer, transferSize });\n }\n allAssets.sort((a, b) => b.co2 - a.co2);\n\n return allAssets.slice(0, allAssets.length > 10 ? 10 : allAssets.length);\n }\n\n perParty(pageXray, greenDomains) {\n let firstParty = 0;\n let thirdParty = 0;\n // calculate co2 per first/third party\n const firstPartyRegEx = pageXray.firstPartyRegEx;\n for (let d of Object.keys(pageXray.domains)) {\n if (!d.match(firstPartyRegEx)) {\n thirdParty += this.perByte(\n pageXray.domains[d].transferSize,\n greenDomains && greenDomains.indexOf(d) > -1\n );\n } else {\n firstParty += this.perByte(\n pageXray.domains[d].transferSize,\n greenDomains && greenDomains.indexOf(d) > -1\n );\n }\n }\n return { firstParty, thirdParty };\n }\n}\n\nexport { CO2 };\nexport default CO2;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,kBAAoB;AAEpB,MAAM,IAAI;AAAA,EACR,YAAY,SAAS;AACnB,SAAK,UAAU;AAGf,SAAK,QAAQ,IAAI,oBAAQ;AAEzB,QAAI,SAAS;AACX,WAAK,QAAQ,IAAI,QAAQ,MAAM;AAAA,IACjC;AAAA,EACF;AAAA,EAWA,QAAQ,OAAO,OAAO;AACpB,WAAO,KAAK,MAAM,QAAQ,OAAO,KAAK;AAAA,EACxC;AAAA,EAEA,UAAU,UAAU,cAAc;AAChC,UAAM,eAAe,CAAC;AACtB,aAAS,UAAU,OAAO,KAAK,SAAS,OAAO,GAAG;AAChD,UAAI;AACJ,UAAI,gBAAgB,aAAa,QAAQ,MAAM,IAAI,IAAI;AACrD,cAAM,KAAK,QAAQ,SAAS,QAAQ,QAAQ,cAAc,IAAI;AAAA,MAChE,OAAO;AACL,cAAM,KAAK,QAAQ,SAAS,QAAQ,QAAQ,YAAY;AAAA,MAC1D;AACA,mBAAa,KAAK;AAAA,QAChB;AAAA,QACA;AAAA,QACA,cAAc,SAAS,QAAQ,QAAQ;AAAA,MACzC,CAAC;AAAA,IACH;AACA,iBAAa,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;AAEzC,WAAO;AAAA,EACT;AAAA,EAEA,QAAQ,UAAU,OAAO;AAQvB,UAAM,YAAY,KAAK,UAAU,UAAU,KAAK;AAChD,QAAI,WAAW;AACf,aAAS,UAAU,WAAW;AAC5B,kBAAY,OAAO;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,UAAU,cAAc;AACrC,UAAM,oBAAoB,CAAC;AAC3B,aAAS,SAAS,SAAS,QAAQ;AACjC,YAAM,SAAS,IAAI,IAAI,MAAM,GAAG,EAAE;AAClC,YAAM,eAAe,MAAM;AAC3B,YAAM,iBAAiB,KAAK,QAC1B,cACA,gBAAgB,aAAa,QAAQ,MAAM,IAAI,EACjD;AACA,YAAM,cAAc,MAAM;AAC1B,UAAI,CAAC,kBAAkB,cAAc;AACnC,0BAAkB,eAAe,EAAE,KAAK,GAAG,cAAc,EAAE;AAAA,MAC7D;AACA,wBAAkB,aAAa,OAAO;AACtC,wBAAkB,aAAa,gBAAgB;AAAA,IACjD;AAEA,UAAM,MAAM,CAAC;AACb,aAAS,QAAQ,OAAO,KAAK,iBAAiB,GAAG;AAC/C,UAAI,KAAK;AAAA,QACP;AAAA,QACA,KAAK,kBAAkB,MAAM;AAAA,QAC7B,cAAc,kBAAkB,MAAM;AAAA,MACxC,CAAC;AAAA,IACH;AACA,QAAI,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;AAChC,WAAO;AAAA,EACT;AAAA,EAEA,kBAAkB,UAAU,cAAc;AACxC,UAAM,YAAY,CAAC;AACnB,aAAS,SAAS,SAAS,QAAQ;AACjC,YAAM,SAAS,IAAI,IAAI,MAAM,GAAG,EAAE;AAClC,YAAM,eAAe,MAAM;AAC3B,YAAM,iBAAiB,KAAK,QAC1B,cACA,gBAAgB,aAAa,QAAQ,MAAM,IAAI,EACjD;AACA,gBAAU,KAAK,EAAE,KAAK,MAAM,KAAK,KAAK,gBAAgB,aAAa,CAAC;AAAA,IACtE;AACA,cAAU,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;AAEtC,WAAO,UAAU,MAAM,GAAG,UAAU,SAAS,KAAK,KAAK,UAAU,MAAM;AAAA,EACzE;AAAA,EAEA,SAAS,UAAU,cAAc;AAC/B,QAAI,aAAa;AACjB,QAAI,aAAa;AAEjB,UAAM,kBAAkB,SAAS;AACjC,aAAS,KAAK,OAAO,KAAK,SAAS,OAAO,GAAG;AAC3C,UAAI,CAAC,EAAE,MAAM,eAAe,GAAG;AAC7B,sBAAc,KAAK,QACjB,SAAS,QAAQ,GAAG,cACpB,gBAAgB,aAAa,QAAQ,CAAC,IAAI,EAC5C;AAAA,MACF,OAAO;AACL,sBAAc,KAAK,QACjB,SAAS,QAAQ,GAAG,cACpB,gBAAgB,aAAa,QAAQ,CAAC,IAAI,EAC5C;AAAA,MACF;AAAA,IACF;AACA,WAAO,EAAE,YAAY,WAAW;AAAA,EAClC;AACF;AAGA,IAAO,cAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,244 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
17
+ var import_fs = __toESM(require("fs"));
18
+ var import_path = __toESM(require("path"));
19
+ var import_pagexray = __toESM(require("pagexray"));
20
+ var import_co2 = __toESM(require("./co2.js"));
21
+ var import_sustainable_web_design = __toESM(require("./sustainable-web-design.js"));
22
+ describe("co2", () => {
23
+ let har, co2;
24
+ describe("1 byte model", () => {
25
+ const TGWF_GREY_VALUE = 0.20497;
26
+ const TGWF_GREEN_VALUE = 0.54704;
27
+ const TGWF_MIXED_VALUE = 0.16718;
28
+ const MILLION = 1e6;
29
+ const MILLION_GREY = 0.29081;
30
+ const MILLION_GREEN = 0.23196;
31
+ beforeEach(() => {
32
+ co2 = new import_co2.default();
33
+ har = JSON.parse(import_fs.default.readFileSync(import_path.default.resolve(__dirname, "../data/fixtures/tgwf.har"), "utf8"));
34
+ });
35
+ describe("perByte", () => {
36
+ it("returns a CO2 number for data transfer using 'grey' power", () => {
37
+ expect(co2.perByte(MILLION).toPrecision(5)).toBe(MILLION_GREY.toPrecision(5));
38
+ });
39
+ it("returns a lower CO2 number for data transfer from domains using entirely 'green' power", () => {
40
+ expect(co2.perByte(MILLION).toPrecision(5)).toBe(MILLION_GREY.toPrecision(5));
41
+ expect(co2.perByte(MILLION, true).toPrecision(5)).toBe(MILLION_GREEN.toPrecision(5));
42
+ });
43
+ });
44
+ describe("perPage", () => {
45
+ it("returns CO2 for total transfer for page", () => {
46
+ const pages = import_pagexray.default.convert(har);
47
+ const pageXrayRun = pages[0];
48
+ expect(co2.perPage(pageXrayRun).toPrecision(5)).toBe(TGWF_GREY_VALUE.toPrecision(5));
49
+ });
50
+ it("returns lower CO2 for page served from green site", () => {
51
+ const pages = import_pagexray.default.convert(har);
52
+ const pageXrayRun = pages[0];
53
+ let green = [
54
+ "www.thegreenwebfoundation.org",
55
+ "fonts.googleapis.com",
56
+ "ajax.googleapis.com",
57
+ "assets.digitalclimatestrike.net",
58
+ "cdnjs.cloudflare.com",
59
+ "graphite.thegreenwebfoundation.org",
60
+ "analytics.thegreenwebfoundation.org",
61
+ "fonts.gstatic.com",
62
+ "api.thegreenwebfoundation.org"
63
+ ];
64
+ expect(co2.perPage(pageXrayRun, green)).toBeLessThan(TGWF_GREY_VALUE);
65
+ });
66
+ it("returns a lower CO2 number where *some* domains use green power", () => {
67
+ const pages = import_pagexray.default.convert(har);
68
+ const pageXrayRun = pages[0];
69
+ let green = [
70
+ "www.thegreenwebfoundation.org",
71
+ "fonts.googleapis.com",
72
+ "ajax.googleapis.com",
73
+ "assets.digitalclimatestrike.net",
74
+ "cdnjs.cloudflare.com",
75
+ "graphite.thegreenwebfoundation.org",
76
+ "analytics.thegreenwebfoundation.org",
77
+ "fonts.gstatic.com",
78
+ "api.thegreenwebfoundation.org"
79
+ ];
80
+ expect(co2.perPage(pageXrayRun, green).toPrecision(5)).toBe(TGWF_MIXED_VALUE.toPrecision(5));
81
+ });
82
+ });
83
+ describe("perDomain", () => {
84
+ it("shows object listing Co2 for each domain", () => {
85
+ const pages = import_pagexray.default.convert(har);
86
+ const pageXrayRun = pages[0];
87
+ const res = co2.perDomain(pageXrayRun);
88
+ const domains = [
89
+ "thegreenwebfoundation.org",
90
+ "www.thegreenwebfoundation.org",
91
+ "maxcdn.bootstrapcdn.com",
92
+ "fonts.googleapis.com",
93
+ "ajax.googleapis.com",
94
+ "assets.digitalclimatestrike.net",
95
+ "cdnjs.cloudflare.com",
96
+ "graphite.thegreenwebfoundation.org",
97
+ "analytics.thegreenwebfoundation.org",
98
+ "fonts.gstatic.com",
99
+ "api.thegreenwebfoundation.org"
100
+ ];
101
+ for (let obj of res) {
102
+ expect(domains.indexOf(obj.domain)).toBeGreaterThan(-1);
103
+ expect(typeof obj.co2).toBe("number");
104
+ }
105
+ });
106
+ it("shows lower Co2 for green domains", () => {
107
+ const pages = import_pagexray.default.convert(har);
108
+ const pageXrayRun = pages[0];
109
+ const greenDomains = [
110
+ "www.thegreenwebfoundation.org",
111
+ "fonts.googleapis.com",
112
+ "ajax.googleapis.com",
113
+ "assets.digitalclimatestrike.net",
114
+ "cdnjs.cloudflare.com",
115
+ "graphite.thegreenwebfoundation.org",
116
+ "analytics.thegreenwebfoundation.org",
117
+ "fonts.gstatic.com",
118
+ "api.thegreenwebfoundation.org"
119
+ ];
120
+ const res = co2.perDomain(pageXrayRun);
121
+ const resWithGreen = co2.perDomain(pageXrayRun, greenDomains);
122
+ for (let obj of res) {
123
+ expect(typeof obj.co2).toBe("number");
124
+ }
125
+ for (let obj of greenDomains) {
126
+ let index = 0;
127
+ expect(resWithGreen[index].co2).toBeLessThan(res[index].co2);
128
+ index++;
129
+ }
130
+ });
131
+ });
132
+ });
133
+ describe("Sustainable Web Design model", () => {
134
+ const MILLION = 1e6;
135
+ const MILLION_GREY = 0.33343;
136
+ const MILLION_GREEN = 0.28908;
137
+ const TGWF_GREY_VALUE = 0.23501;
138
+ const TGWF_GREEN_VALUE = 0.54704;
139
+ const TGWF_MIXED_VALUE = 0.20652;
140
+ beforeEach(() => {
141
+ co2 = new import_co2.default({ model: import_sustainable_web_design.default });
142
+ har = JSON.parse(import_fs.default.readFileSync(import_path.default.resolve(__dirname, "../data/fixtures/tgwf.har"), "utf8"));
143
+ });
144
+ describe("perByte", () => {
145
+ it("returns a CO2 number for data transfer", () => {
146
+ co2.perByte(MILLION);
147
+ expect(co2.perByte(MILLION).toPrecision(5)).toBe(MILLION_GREY.toPrecision(5));
148
+ });
149
+ it("returns a lower CO2 number for data transfer from domains using entirely 'green' power", () => {
150
+ expect(co2.perByte(MILLION, false).toPrecision(5)).toBe(MILLION_GREY.toPrecision(5));
151
+ expect(co2.perByte(MILLION, true).toPrecision(5)).toBe(MILLION_GREEN.toPrecision(5));
152
+ });
153
+ });
154
+ describe("perPage", () => {
155
+ it("returns CO2 for total transfer for page", () => {
156
+ const pages = import_pagexray.default.convert(har);
157
+ const pageXrayRun = pages[0];
158
+ expect(co2.perPage(pageXrayRun).toPrecision(5)).toBe(TGWF_GREY_VALUE.toPrecision(5));
159
+ });
160
+ it("returns lower CO2 for page served from green site", () => {
161
+ const pages = import_pagexray.default.convert(har);
162
+ const pageXrayRun = pages[0];
163
+ let green = [
164
+ "www.thegreenwebfoundation.org",
165
+ "fonts.googleapis.com",
166
+ "ajax.googleapis.com",
167
+ "assets.digitalclimatestrike.net",
168
+ "cdnjs.cloudflare.com",
169
+ "graphite.thegreenwebfoundation.org",
170
+ "analytics.thegreenwebfoundation.org",
171
+ "fonts.gstatic.com",
172
+ "api.thegreenwebfoundation.org"
173
+ ];
174
+ expect(co2.perPage(pageXrayRun, green)).toBeLessThan(TGWF_GREY_VALUE);
175
+ });
176
+ it("returns a lower CO2 number where *some* domains use green power", () => {
177
+ const pages = import_pagexray.default.convert(har);
178
+ const pageXrayRun = pages[0];
179
+ let green = [
180
+ "www.thegreenwebfoundation.org",
181
+ "fonts.googleapis.com",
182
+ "ajax.googleapis.com",
183
+ "assets.digitalclimatestrike.net",
184
+ "cdnjs.cloudflare.com",
185
+ "graphite.thegreenwebfoundation.org",
186
+ "analytics.thegreenwebfoundation.org",
187
+ "fonts.gstatic.com",
188
+ "api.thegreenwebfoundation.org"
189
+ ];
190
+ expect(co2.perPage(pageXrayRun, green).toPrecision(5)).toBe(TGWF_MIXED_VALUE.toPrecision(5));
191
+ });
192
+ });
193
+ describe("perDomain", () => {
194
+ it("shows object listing Co2 for each domain", () => {
195
+ const pages = import_pagexray.default.convert(har);
196
+ const pageXrayRun = pages[0];
197
+ const res = co2.perDomain(pageXrayRun);
198
+ const domains = [
199
+ "thegreenwebfoundation.org",
200
+ "www.thegreenwebfoundation.org",
201
+ "maxcdn.bootstrapcdn.com",
202
+ "fonts.googleapis.com",
203
+ "ajax.googleapis.com",
204
+ "assets.digitalclimatestrike.net",
205
+ "cdnjs.cloudflare.com",
206
+ "graphite.thegreenwebfoundation.org",
207
+ "analytics.thegreenwebfoundation.org",
208
+ "fonts.gstatic.com",
209
+ "api.thegreenwebfoundation.org"
210
+ ];
211
+ for (let obj of res) {
212
+ expect(domains.indexOf(obj.domain)).toBeGreaterThan(-1);
213
+ expect(typeof obj.co2).toBe("number");
214
+ }
215
+ });
216
+ it("shows lower Co2 for green domains", () => {
217
+ const pages = import_pagexray.default.convert(har);
218
+ const pageXrayRun = pages[0];
219
+ const greenDomains = [
220
+ "www.thegreenwebfoundation.org",
221
+ "fonts.googleapis.com",
222
+ "ajax.googleapis.com",
223
+ "assets.digitalclimatestrike.net",
224
+ "cdnjs.cloudflare.com",
225
+ "graphite.thegreenwebfoundation.org",
226
+ "analytics.thegreenwebfoundation.org",
227
+ "fonts.gstatic.com",
228
+ "api.thegreenwebfoundation.org"
229
+ ];
230
+ const res = co2.perDomain(pageXrayRun);
231
+ const resWithGreen = co2.perDomain(pageXrayRun, greenDomains);
232
+ for (let obj of res) {
233
+ expect(typeof obj.co2).toBe("number");
234
+ }
235
+ for (let obj of greenDomains) {
236
+ let index = 0;
237
+ expect(resWithGreen[index].co2).toBeLessThan(res[index].co2);
238
+ index++;
239
+ }
240
+ });
241
+ });
242
+ });
243
+ });
244
+ //# sourceMappingURL=co2.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/co2.test.js"],
4
+ "sourcesContent": ["\"use strict\";\n\nimport fs from \"fs\";\nimport path from \"path\";\n\nimport pagexray from \"pagexray\";\n\nimport CO2 from \"./co2.js\";\nimport swd from \"./sustainable-web-design.js\";\n\ndescribe(\"co2\", () => {\n let har, co2;\n\n describe(\"1 byte model\", () => {\n const TGWF_GREY_VALUE = 0.20497;\n const TGWF_GREEN_VALUE = 0.54704;\n const TGWF_MIXED_VALUE = 0.16718;\n\n const MILLION = 1000000;\n const MILLION_GREY = 0.29081;\n const MILLION_GREEN = 0.23196;\n\n beforeEach(() => {\n co2 = new CO2();\n har = JSON.parse(\n fs.readFileSync(\n path.resolve(__dirname, \"../data/fixtures/tgwf.har\"),\n \"utf8\"\n )\n );\n });\n\n describe(\"perByte\", () => {\n it(\"returns a CO2 number for data transfer using 'grey' power\", () => {\n expect(co2.perByte(MILLION).toPrecision(5)).toBe(\n MILLION_GREY.toPrecision(5)\n );\n });\n\n it(\"returns a lower CO2 number for data transfer from domains using entirely 'green' power\", () => {\n expect(co2.perByte(MILLION).toPrecision(5)).toBe(\n MILLION_GREY.toPrecision(5)\n );\n expect(co2.perByte(MILLION, true).toPrecision(5)).toBe(\n MILLION_GREEN.toPrecision(5)\n );\n });\n });\n\n describe(\"perPage\", () => {\n it(\"returns CO2 for total transfer for page\", () => {\n const pages = pagexray.convert(har);\n const pageXrayRun = pages[0];\n\n expect(co2.perPage(pageXrayRun).toPrecision(5)).toBe(\n TGWF_GREY_VALUE.toPrecision(5)\n );\n });\n it(\"returns lower CO2 for page served from green site\", () => {\n const pages = pagexray.convert(har);\n const pageXrayRun = pages[0];\n let green = [\n \"www.thegreenwebfoundation.org\",\n \"fonts.googleapis.com\",\n \"ajax.googleapis.com\",\n \"assets.digitalclimatestrike.net\",\n \"cdnjs.cloudflare.com\",\n \"graphite.thegreenwebfoundation.org\",\n \"analytics.thegreenwebfoundation.org\",\n \"fonts.gstatic.com\",\n \"api.thegreenwebfoundation.org\",\n ];\n expect(co2.perPage(pageXrayRun, green)).toBeLessThan(TGWF_GREY_VALUE);\n });\n it(\"returns a lower CO2 number where *some* domains use green power\", () => {\n const pages = pagexray.convert(har);\n const pageXrayRun = pages[0];\n // green can be true, or a array containing entries\n let green = [\n \"www.thegreenwebfoundation.org\",\n \"fonts.googleapis.com\",\n \"ajax.googleapis.com\",\n \"assets.digitalclimatestrike.net\",\n \"cdnjs.cloudflare.com\",\n \"graphite.thegreenwebfoundation.org\",\n \"analytics.thegreenwebfoundation.org\",\n \"fonts.gstatic.com\",\n \"api.thegreenwebfoundation.org\",\n ];\n expect(co2.perPage(pageXrayRun, green).toPrecision(5)).toBe(\n TGWF_MIXED_VALUE.toPrecision(5)\n );\n });\n });\n describe(\"perDomain\", () => {\n it(\"shows object listing Co2 for each domain\", () => {\n const pages = pagexray.convert(har);\n const pageXrayRun = pages[0];\n const res = co2.perDomain(pageXrayRun);\n\n const domains = [\n \"thegreenwebfoundation.org\",\n \"www.thegreenwebfoundation.org\",\n \"maxcdn.bootstrapcdn.com\",\n \"fonts.googleapis.com\",\n \"ajax.googleapis.com\",\n \"assets.digitalclimatestrike.net\",\n \"cdnjs.cloudflare.com\",\n \"graphite.thegreenwebfoundation.org\",\n \"analytics.thegreenwebfoundation.org\",\n \"fonts.gstatic.com\",\n \"api.thegreenwebfoundation.org\",\n ];\n\n for (let obj of res) {\n expect(domains.indexOf(obj.domain)).toBeGreaterThan(-1);\n expect(typeof obj.co2).toBe(\"number\");\n }\n });\n it(\"shows lower Co2 for green domains\", () => {\n const pages = pagexray.convert(har);\n const pageXrayRun = pages[0];\n\n const greenDomains = [\n \"www.thegreenwebfoundation.org\",\n \"fonts.googleapis.com\",\n \"ajax.googleapis.com\",\n \"assets.digitalclimatestrike.net\",\n \"cdnjs.cloudflare.com\",\n \"graphite.thegreenwebfoundation.org\",\n \"analytics.thegreenwebfoundation.org\",\n \"fonts.gstatic.com\",\n \"api.thegreenwebfoundation.org\",\n ];\n const res = co2.perDomain(pageXrayRun);\n const resWithGreen = co2.perDomain(pageXrayRun, greenDomains);\n\n for (let obj of res) {\n expect(typeof obj.co2).toBe(\"number\");\n }\n for (let obj of greenDomains) {\n let index = 0;\n expect(resWithGreen[index].co2).toBeLessThan(res[index].co2);\n index++;\n }\n });\n });\n });\n\n describe(\"Sustainable Web Design model\", () => {\n // the SWD model should have slightly higher values as\n // we include more of the system in calculations for the\n // same levels of data transfer\n const MILLION = 1000000;\n const MILLION_GREY = 0.33343;\n const MILLION_GREEN = 0.28908;\n\n const TGWF_GREY_VALUE = 0.23501;\n const TGWF_GREEN_VALUE = 0.54704;\n const TGWF_MIXED_VALUE = 0.20652;\n\n beforeEach(() => {\n co2 = new CO2({ model: swd });\n har = JSON.parse(\n fs.readFileSync(\n path.resolve(__dirname, \"../data/fixtures/tgwf.har\"),\n \"utf8\"\n )\n );\n });\n\n describe(\"perByte\", () => {\n it(\"returns a CO2 number for data transfer\", () => {\n co2.perByte(MILLION);\n expect(co2.perByte(MILLION).toPrecision(5)).toBe(\n MILLION_GREY.toPrecision(5)\n );\n });\n\n it(\"returns a lower CO2 number for data transfer from domains using entirely 'green' power\", () => {\n expect(co2.perByte(MILLION, false).toPrecision(5)).toBe(\n MILLION_GREY.toPrecision(5)\n );\n\n expect(co2.perByte(MILLION, true).toPrecision(5)).toBe(\n MILLION_GREEN.toPrecision(5)\n );\n });\n });\n\n describe(\"perPage\", () => {\n it(\"returns CO2 for total transfer for page\", () => {\n const pages = pagexray.convert(har);\n const pageXrayRun = pages[0];\n\n expect(co2.perPage(pageXrayRun).toPrecision(5)).toBe(\n TGWF_GREY_VALUE.toPrecision(5)\n );\n });\n it(\"returns lower CO2 for page served from green site\", () => {\n const pages = pagexray.convert(har);\n const pageXrayRun = pages[0];\n let green = [\n \"www.thegreenwebfoundation.org\",\n \"fonts.googleapis.com\",\n \"ajax.googleapis.com\",\n \"assets.digitalclimatestrike.net\",\n \"cdnjs.cloudflare.com\",\n \"graphite.thegreenwebfoundation.org\",\n \"analytics.thegreenwebfoundation.org\",\n \"fonts.gstatic.com\",\n \"api.thegreenwebfoundation.org\",\n ];\n expect(co2.perPage(pageXrayRun, green)).toBeLessThan(TGWF_GREY_VALUE);\n });\n it(\"returns a lower CO2 number where *some* domains use green power\", () => {\n const pages = pagexray.convert(har);\n const pageXrayRun = pages[0];\n // green can be true, or a array containing entries\n let green = [\n \"www.thegreenwebfoundation.org\",\n \"fonts.googleapis.com\",\n \"ajax.googleapis.com\",\n \"assets.digitalclimatestrike.net\",\n \"cdnjs.cloudflare.com\",\n \"graphite.thegreenwebfoundation.org\",\n \"analytics.thegreenwebfoundation.org\",\n \"fonts.gstatic.com\",\n \"api.thegreenwebfoundation.org\",\n ];\n expect(co2.perPage(pageXrayRun, green).toPrecision(5)).toBe(\n TGWF_MIXED_VALUE.toPrecision(5)\n );\n });\n });\n describe(\"perDomain\", () => {\n it(\"shows object listing Co2 for each domain\", () => {\n const pages = pagexray.convert(har);\n const pageXrayRun = pages[0];\n const res = co2.perDomain(pageXrayRun);\n\n const domains = [\n \"thegreenwebfoundation.org\",\n \"www.thegreenwebfoundation.org\",\n \"maxcdn.bootstrapcdn.com\",\n \"fonts.googleapis.com\",\n \"ajax.googleapis.com\",\n \"assets.digitalclimatestrike.net\",\n \"cdnjs.cloudflare.com\",\n \"graphite.thegreenwebfoundation.org\",\n \"analytics.thegreenwebfoundation.org\",\n \"fonts.gstatic.com\",\n \"api.thegreenwebfoundation.org\",\n ];\n\n for (let obj of res) {\n expect(domains.indexOf(obj.domain)).toBeGreaterThan(-1);\n expect(typeof obj.co2).toBe(\"number\");\n }\n });\n it(\"shows lower Co2 for green domains\", () => {\n const pages = pagexray.convert(har);\n const pageXrayRun = pages[0];\n\n const greenDomains = [\n \"www.thegreenwebfoundation.org\",\n \"fonts.googleapis.com\",\n \"ajax.googleapis.com\",\n \"assets.digitalclimatestrike.net\",\n \"cdnjs.cloudflare.com\",\n \"graphite.thegreenwebfoundation.org\",\n \"analytics.thegreenwebfoundation.org\",\n \"fonts.gstatic.com\",\n \"api.thegreenwebfoundation.org\",\n ];\n const res = co2.perDomain(pageXrayRun);\n const resWithGreen = co2.perDomain(pageXrayRun, greenDomains);\n\n for (let obj of res) {\n expect(typeof obj.co2).toBe(\"number\");\n }\n for (let obj of greenDomains) {\n let index = 0;\n expect(resWithGreen[index].co2).toBeLessThan(res[index].co2);\n index++;\n }\n });\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }