From 6a31f1c57339bc64f2d033768a09b522ab257e4a Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Tue, 25 Aug 2020 20:20:02 +0300
Subject: [PATCH 01/39] Add VSCode settings
---
.vscode/settings.json | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 .vscode/settings.json
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..c8ff90094
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,16 @@
+{
+ "editor.tabSize": 2,
+ "editor.insertSpaces": true,
+ "editor.detectIndentation": false,
+ "eslint.autoFixOnSave": true,
+ "git.detectSubmodules": false,
+ "editor.rulers": [
+ 80
+ ],
+ "files.insertFinalNewline": true,
+ "editor.codeActionsOnSave": {
+ "source.fixAll.eslint": true
+ },
+ "diffEditor.ignoreTrimWhitespace": false,
+ "files.trimTrailingWhitespace": true
+}
From 8d77d5f4072c7b224d4e6a08043c00e49db40c13 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Tue, 25 Aug 2020 21:30:41 +0300
Subject: [PATCH 02/39] Replace kleur with chalk
---
gatsby-node.js | 2 +-
package-lock.json | 642 +++++++++++++++++++++++++++++++++++-
package.json | 2 +-
src/yild/logOutput/index.js | 11 +-
4 files changed, 644 insertions(+), 13 deletions(-)
diff --git a/gatsby-node.js b/gatsby-node.js
index 802fc2e96..a267e81ce 100644
--- a/gatsby-node.js
+++ b/gatsby-node.js
@@ -1,4 +1,4 @@
-const { green } = require('kleur');
+const { green } = require('chalk');
const env = require('./.build/env').default;
const {
diff --git a/package-lock.json b/package-lock.json
index 11a468d80..acecdd38a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -258,6 +258,19 @@
"@babel/helper-validator-identifier": "^7.10.4",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"@babel/parser": {
@@ -507,6 +520,19 @@
"@babel/helper-validator-identifier": "^7.9.0",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"@babel/parser": {
@@ -740,6 +766,19 @@
"@babel/helper-validator-identifier": "^7.10.1",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"@babel/parser": {
@@ -1914,6 +1953,17 @@
"slash": "^2.0.0"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"slash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
@@ -1970,6 +2020,17 @@
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"slash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
@@ -2045,6 +2106,17 @@
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"slash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
@@ -2144,6 +2216,17 @@
"write-file-atomic": "2.4.1"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"slash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
@@ -2254,6 +2337,17 @@
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
@@ -2412,6 +2506,19 @@
"string-width": "^2.1.0",
"strip-ansi": "^5.1.0",
"through": "^2.3.6"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"is-fullwidth-code-point": {
@@ -2538,6 +2645,19 @@
"sockjs-client": "1.4.0",
"strip-ansi": "5.2.0",
"text-table": "0.2.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"react-error-overlay": {
@@ -4272,6 +4392,28 @@
"integrity": "sha512-AEzsGvjBJL0lby/87W96PyEvwN0GsYvk5LHsglLg9tW37K4BqvAvoSCdWIE13OZQ8afupqZ73+oL/1LkedN8hA==",
"dev": true
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
"electron-to-chromium": {
"version": "1.3.458",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.458.tgz",
@@ -5615,6 +5757,17 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
"integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
"dev": true
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
}
}
},
@@ -5973,14 +6126,55 @@
"dev": true
},
"chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
"requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
}
},
"character-entities": {
@@ -6450,6 +6644,19 @@
"@types/q": "^1.5.1",
"chalk": "^2.4.1",
"q": "^1.1.2"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"code-point-at": {
@@ -6649,6 +6856,28 @@
"yargs": "^13.3.0"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
"date-fns": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.15.0.tgz",
@@ -7571,6 +7800,34 @@
"integrity": "sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ==",
"dev": true
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
"commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@@ -8823,6 +9080,17 @@
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
@@ -10121,6 +10389,17 @@
"worker-rpc": "^0.1.0"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"chokidar": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
@@ -12578,6 +12857,43 @@
"integrity": "sha512-AEzsGvjBJL0lby/87W96PyEvwN0GsYvk5LHsglLg9tW37K4BqvAvoSCdWIE13OZQ8afupqZ73+oL/1LkedN8hA==",
"dev": true
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ }
+ }
+ },
"chokidar": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz",
@@ -14092,6 +14408,19 @@
"@babel/helper-validator-identifier": "^7.10.1",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"@babel/runtime": {
@@ -15769,6 +16098,19 @@
"term-size": "^1.2.0",
"type-fest": "^0.3.0",
"widest-line": "^2.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"cross-spawn": {
@@ -16863,6 +17205,19 @@
"prompts": "^2.0.1",
"realpath-native": "^1.1.0",
"yargs": "^13.3.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
}
}
@@ -17006,6 +17361,17 @@
"babel-plugin-jest-hoist": "^24.9.0"
}
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"slash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
@@ -17024,6 +17390,19 @@
"diff-sequences": "^24.9.0",
"jest-get-type": "^24.9.0",
"pretty-format": "^24.9.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"jest-docblock": {
@@ -17046,6 +17425,19 @@
"jest-get-type": "^24.9.0",
"jest-util": "^24.9.0",
"pretty-format": "^24.9.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"jest-environment-jsdom": {
@@ -17215,6 +17607,19 @@
"jest-util": "^24.9.0",
"pretty-format": "^24.9.0",
"throat": "^4.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"jest-leak-detector": {
@@ -17237,6 +17642,19 @@
"jest-diff": "^24.9.0",
"jest-get-type": "^24.9.0",
"pretty-format": "^24.9.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"jest-message-util": {
@@ -17255,6 +17673,17 @@
"stack-utils": "^1.0.1"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"slash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
@@ -17295,6 +17724,19 @@
"chalk": "^2.0.1",
"jest-pnp-resolver": "^1.2.1",
"realpath-native": "^1.1.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"jest-resolve-dependencies": {
@@ -17333,6 +17775,19 @@
"jest-worker": "^24.6.0",
"source-map-support": "^0.5.6",
"throat": "^4.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"jest-runtime": {
@@ -17366,6 +17821,17 @@
"yargs": "^13.3.0"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"slash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
@@ -17401,6 +17867,17 @@
"semver": "^6.2.0"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -17435,6 +17912,17 @@
"source-map": "^0.6.0"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"is-ci": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
@@ -17470,6 +17958,19 @@
"jest-get-type": "^24.9.0",
"leven": "^3.1.0",
"pretty-format": "^24.9.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"jest-watcher": {
@@ -17499,6 +18000,17 @@
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"string-length": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz",
@@ -17943,6 +18455,17 @@
"figures": "^2.0.0"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"cli-cursor": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
@@ -18267,6 +18790,19 @@
"dev": true,
"requires": {
"chalk": "^2.4.2"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"log-update": {
@@ -19472,6 +20008,19 @@
"string-width": "^2.0.0",
"term-size": "^1.2.0",
"widest-line": "^2.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"camelcase": {
@@ -19782,6 +20331,19 @@
"latest-version": "^3.0.0",
"semver-diff": "^2.0.0",
"xdg-basedir": "^3.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"url-parse-lax": {
@@ -20893,6 +21455,28 @@
"supports-color": "^6.1.0"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -23086,6 +23670,19 @@
"@babel/helper-validator-identifier": "^7.10.4",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
}
},
"@babel/parser": {
@@ -25266,6 +25863,17 @@
"util.promisify": "~1.0.0"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"css-select": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
@@ -27077,6 +27685,17 @@
"webpack-sources": "^1.0.0"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"schema-utils": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
@@ -28017,6 +28636,17 @@
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"is-ci": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
diff --git a/package.json b/package.json
index 930dc41e8..3d3f4fd68 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"@testing-library/react": "^10.4.8",
"babel-jest": "^26.3.0",
"babel-loader": "^8.0.6",
+ "chalk": "^4.1.0",
"copy-to-clipboard": "^3.3.1",
"cross-env": "^6.0.3",
"css-loader": "^3.4.2",
@@ -41,7 +42,6 @@
"jest": "^24.9.0",
"jest-environment-jsdom-fourteen": "^1.0.1",
"jest-transform-stub": "^2.0.0",
- "kleur": "^3.0.3",
"mdast-util-to-hast": "^9.1.0",
"node-sass": "^4.14.1",
"npm-watch": "^0.6.0",
diff --git a/src/yild/logOutput/index.js b/src/yild/logOutput/index.js
index d58db3b1c..f1cbf021b 100644
--- a/src/yild/logOutput/index.js
+++ b/src/yild/logOutput/index.js
@@ -1,15 +1,16 @@
-import kleur, { bold, blue, green, red, yellow } from 'kleur';
+import chalk from 'chalk';
import process from 'process';
+const { bold, blue, green, red, yellow } = chalk;
global._yild_logOutput_instance = undefined;
/**
- * Format a string with the given kleur formatter.
+ * Format a string with the given chalk formatter.
* @param {string} msg - The message to be formatted.
- * @param {array} format - The name of the kleur function(s) to use.
+ * @param {array} format - The name of the chalk function(s) to use.
*/
export const format = (msg, ...format) =>
- format.reduce((m, f) => kleur[f] ? kleur[f](m) : m, msg);
+ format.reduce((m, f) => chalk[f] ? chalk[f](m) : m, msg);
/**
* Logger class-like, should be used to have a logger singleton.
@@ -57,7 +58,7 @@ function logger() {
let message = breakLine ? `${msg}\n` : `${msg}`;
if(procName) message = `[${bold(procName)}] ${message}`;
- if(validTypes.includes(type)) message = `${prefixes[type]} | ${message}`;
+ if(validTypes.includes(type)) message = `${prefixes[type]} ${message}`;
this.outputStream.write(message);
};
From 3a7a6565d9be71b0097834d42078af18e232e466 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Tue, 25 Aug 2020 22:56:05 +0300
Subject: [PATCH 03/39] Merge language background generation into icon
generation
Combine steps by using one template for both.
---
assets/icons.woff2 | Bin 2704 -> 2696 bytes
package.json | 2 +-
src/config/icons.json | 6 +++-
src/config/paths.json | 1 -
src/styles/_icon_colors.scss | 46 --------------------------
src/styles/_icons.scss | 42 ++++++++++++++++++++++-
src/styles/index.scss | 1 -
src/yild/core/actions.js | 7 ----
src/yild/makeIcons/cssTemplate.hbs | 11 ++++++
src/yild/makeIcons/index.js | 11 ++++--
src/yild/makeLangBackgrounds/index.js | 33 ------------------
11 files changed, 67 insertions(+), 93 deletions(-)
delete mode 100644 src/styles/_icon_colors.scss
delete mode 100644 src/yild/makeLangBackgrounds/index.js
diff --git a/assets/icons.woff2 b/assets/icons.woff2
index 159b87368fa293d8dfc07a1e5cdd933911204d53..e8d67afa27563ffceb382a1cfa2164d5f7861b23 100644
GIT binary patch
delta 2661
zcmV-r3Yzth6^IoWcTYw#00961000Vz01E&B000;S000U)kr+UKM`8@lqaV?QJ~x``
z|K(ye9KRtMbqn>(#Sg*rK@V)^fX
zs!}`Z+F~uvBG93K$oKtizdN1nNY0X#y_7MAnl4yazyjdd3wHz5S3*i4uff{%a1~&&
zumHPWo&^Df$ukQ%JZI4=;#(Vgx6_S=elFnOQf%F{p@Dafq7^R%Uc?cscUatn0hV(W
z;Pbye6NfZNjDj9w+4}lgDnH>*?VJQ6oGQ}-a;sLr*!rY@i{nD;AWE+qiz586G>g=v
z(c!1|W)prAwy(AVc8Nk`p4)Np2oWYilo)YZu;f3y1g#`#qaB0;Z5{;>ov3bypM*(p
zmLR|i1XzOr8xUXz1lR=u_CSC`Ai!Y|;0OqC6a+X10vrbcZUF(dAizEdZ~_Fl6$Cg5
z0^9}y+>SVZEag?kjsruXp9+;kh)g0FgnIq3o;I
zJ?C>yAM_}kmSi#+Ex|X-yck!f;>5t^{-+?La0tK}Sr?@%5(!;j;2GgWk6A>q1zMgt
zUgz!4W7O3lqC;zxQZiIA7^unF>4X|Ypa2r=F3{l#dN7@+jm+O{DB(yN5Mk(3F7TrH^F3|DWEGQ9+
z7yuti<4kvE0*;c5I?975cy<4>5NvaQce8EmEDHX+*yYwR{`x}e=kj>!vF^bhe_`^7
zQ*3xCUR1;RavT(!rX@XR
z|M!nEhbJtRfm)yfZBKj7SNzvs_m#lV{LR|L@GbfxCVUCJ>8V5kxEe|hP``wKq+SQo
znPpG;h4>2>7seM3`8$@ThNm95HGFHyQ(i%G@s@9Tddxw)pqln#`Jvk*OR~pZI7Cdg
zttpxBHn$fT*00CVyFwW8`scy~#x{S;HLYRg8llDOuL~XMpj+2z#;mbV4iqM9#zg+~
z^VicYGq71^7o~_mW#NaVeyrVwGO6Q^btub=-^1A4`>|
zm~jYAEv0fQRr}`ePyPSDfiv<0rfGXGyM1jF39B>8A4W6mtKG*)M)b+#d67GC-9pE8
zlw(M}pXX<}%XQpi(J@z!&YpD$y&iJr-xj?+x$>$pQKHlD@3=n(epADLYT7cS&Iq?~
z_uYjY87)~hO%FLkdRoOg86iw)K~a(7IHj#jQ^SPjgWrzj#BbpDg7^XKdDq|Q@$ThX#g
z26Flg6CAZ|cP_aL+)Ivs2S1Qt%G4&d+se1+`S0oPLG!e)1bKh!RzDwTpKkZI!9wc_
zci0^p8EZP~tBdXnLmP@`!b6Uv;HFD$Zf@1?$Ze&3dQE892tWNnZ9yjK;isX}9aJ$IE;_sS}v+y$X$
z6EPmioHAyn)BT1~Oxq@Hea&n~C|~%dSPx9ZWG)MgmX_JI6qot(UiE5Lwn;nD%9yaj
zR<^9O64PXC#YI$EM|CmC=%^_HZ$Y`|vXIqGxLZJ@^x>A)
z$=9u~rdqc?*iv1i)D*W4KqJ^D7fP)I4A61CN9h6JyPGlwz-B1b09*rQ2%zJRyHW$F
zGOM)<73|G_Pc^7HUkIdp^%yX-8zuaO*Z?SsfXlE3ejxq;`?En&AT*e_AU4~4=<~zF
zn)*CEq%^7}`uo>^+kf_bXM>!<@#gZ#uz!wCTR5_Y6|
z-}0;yB$ACl91~77X(oNw9soBhM$`m-*l{$>J?9<7_FE=E87l?&56!9JZGCbOHFk3V
zi5%)5NBeM_w*gU#s)$OHw3YD^Prw)
z?tl=E?r;|C>lqa!ikO~o77$DHctRu-y}gd;pY~WR1|JIsC1p1RmjV$6T0mFU^s028%AdM^
zx)DXU**e7p;w-HwjUH5kzhz_8R<}Cf&fnZ=6)M!pNfpa~|5KIPQP&o0aTb9NMZWKE
z``zhmM{<^|?4^u;Cj^-aD*OzmcUUp33T{lsvG`Dwy(AV
zb_Nas`P`0y0D=f1j0mELAr4Lc!%JWYNem+ekOFNU0RS3Bbqe?+nFP)Z1TY5yEIg8()`04G2I4}kzqf&d-{0h~e{
zEMUZLp964z29U2o+V?=8yc=~43dBqfMNERUg%Bl~HVTdi2oz03>8nXQvF9yXBvmwF
zMkmG8LLd;#$EH%Ixhblp2DLHGY#~3Zby-9OvSc{IGJ;Vk!R=)x=QH1fd0JDV;m@tf
zg^R8~82OU-ayjN}*|_uYSi;MR%s)EfyK1sa5z|b6lR$n%cN!WVk$Xc`0G@G@Zt=1Z
z`y1<#e-vI3GhO^m1P{dXg*w+d`qc6we1Zsx-!0Lu4h3kTFuVFHqJ$51D#O3drZ?~)ZZr}bHV)!k5c1yuE5B^K;~n@
z$H?1%PXzpI?xr*DghQd3%_wJe$FtntR^Q(LJRFxVD2?1k{rovg4{j(7OyM+GXmkUE
zCTGstBF4;@7Ms?Ng(t}w{<@<`TYyIQBeJt8cQ!U{zZ5erp&c)~?}!Qw5M>t4!?8!Q
z1a~`TXt?WXmf92OS%>J+F&Dd1_?Wot%ve)@?GyBRS3Vw|OY;g48AKV%zIxqrKIim7
zkHTq5CX>+;e6!4padj$A3|#Ji3Ni|Z0IZR9QMw|L(DenL5l-}&MHE}0<(cDk-u^sB
zT^%Aiv_>f%Y(uv8{V;$o}G*;=djE|WIg78
zUu*l7Ap`z=ogU9_`s-DC9NKF499tQ+gJ~w>`PMiXhl&TYk_wAvM{?1Pq}sfOn4C7V
zSt8=%C3*RRiey??3iD8{l;n(OJ~wi?Ziz%f3u9`Ol3i@k{R8I$9iPpD60wK@@S!x$
zbY~{uD9Na!Ja~dv_b&^{LqI?VN3k~H|zgN{2Wb+lF5M2eJT+ER-t48_2L}a^LLzoYUrt}F9^M0-c!CC3~RT1IWZv*+L~(GwS{*Z6KtMM7)SOI6K$tt
zewn#FTcTEj#N=s`^r0`2w59(4Z@K?#i8Brf`p}0+*dpkzI)TlOezL7F;cSll>6bo~
zZkd^7mSHEj&2}@JpZG5qX11_@S=d-JP8he1-6o!Z6jYoQHDM7mEL`rz=5MsZ7Pj97
zfxQ;ba%=B5e_;J@8o1>LOcVBAJX7dILW>MHOAsiT+&e}xqEDWDFmeZ6JE9E5l_B+h
zo}cBVhBEGpY`(Z@_ECl4hl1+R3nMQ|Zo0HNg2=X4jl6R+{>n>y@g$gk$dFNd*~^Ls
zGJ@gcqS&YQiN)PoWr$>G!JJ@poKo*zy6eW7iU$hEH?sMio
zp8n!oBO_lQ-2LFWJHw+t*jLZ+BvF=F#9TNj%EEZxY3MY2LBQGbaF&feR9NDOpJg`N
zHp2u*VcXShxEx9e?IL5OOnj=r}w5a$w2n(!ZwS9Cc`yq2aq`+_g)6;Z;j|ujZ19V@g$e
z<#OpYLdwscbKfhac+uH%xmQtYtVohaX*2$+FNDAN%H^5wQ39Vi=e{SP_s&eb@{7Ob
z$;;!jLoa{%!GnhmhQrnp>yrGTDSJNlxGZj1$?)U7Cc$QZH=OB*P7mbZR5i6eo4Rg|
zNp-Wgzf^jStY)mqGN!rtQmc^4u1{4@MY4Uo+@KpUXTib~{Ks>Kp7W0(dpDKHyN`@*
z`}EkSwvQcs*O9mudUfjnG{UjPW@7^k&}qL%$pP?lH{~e+9Dx!C;8rLL0G&?U6%DAW
z#?@Mcz4^_5IpJ>OLUMKBF1-8OPn9#!+QA=x3}36ge(#O=_P+)g4+8wi8T+r^
zw>&F=k!*rECLU~>Y3$kq;1R`$nxGFmjz+oXd=An5mI;JdDe!+ZNBeAja)^xG9AFIc
zkNg{oz%A~Y@lsd{)j5<#e8^_m^}~jo!chf5LYB06CZ-e5h1}~FcOQ?JQl1;HguFIB
z-C%6j#bPR4qxMd+i|^$?=D%@yR818KIi*2
ztLAmv*8XnCcU!Hl)$_W`uH)w#zTaES=WC*Wnsd5sGCD`c8Azt!Sz6v_4<+JohOA
z0+U;catbQ<0j;A>Ug2{snN@e$jr#`b=4PFLS!0=q%-DV;I{fm7;zFLNs&PT3hu_PKSEK8QJgfHl%OF>(lDiH
zghmlMJ+HgEwdK})QEheW(rLKPt%%)w;B`A&m%6JRmxvIKqJ`J2H~i4?NGrXd(`xoi
zs@;mWWH{X=x94`0({EI~9(S&+uj<`arBfG;Zrf$cebH+6eco&IRPQdo(d|gjtvJ5w
bAM!n?5x~xTzuBqxMc=P@hQHeMeb)m3(V;AP
diff --git a/package.json b/package.json
index 3d3f4fd68..8df0d3f27 100644
--- a/package.json
+++ b/package.json
@@ -74,7 +74,7 @@
"watch-assets": "npm-watch prepare-assets",
"serve-snippets": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -n=DEVELOPMENT -s",
"yild": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js",
- "prebuild": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -u -a -e -i -b -n=PRODUCTION -c",
+ "prebuild": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -u -a -e -i -n=PRODUCTION -c",
"predevelop": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -n=DEVELOPMENT -c",
"pretest": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -n=DEVELOPMENT -c",
"build": "NODE_PATH=src npx --node-arg '-r esm' gatsby build",
diff --git a/src/config/icons.json b/src/config/icons.json
index 7ce272e06..d2b66166f 100644
--- a/src/config/icons.json
+++ b/src/config/icons.json
@@ -5,5 +5,9 @@
"cssTemplatePath": "src/yild/makeIcons/cssTemplate.hbs",
"cssSelector": ".icon",
"cssClassName": "icon",
- "cssClassPrefix": "icon-"
+ "cssClassPrefix": "icon-",
+ "cssLanguageSelectors": [
+ ".card-icon",
+ ".btn"
+ ]
}
diff --git a/src/config/paths.json b/src/config/paths.json
index cfcc9f0d0..4c57fdd79 100644
--- a/src/config/paths.json
+++ b/src/config/paths.json
@@ -7,7 +7,6 @@
"buildPath": ".build",
"rawIconPath": "src/icons/*.svg",
"iconFontPath": "src/styles/_icons.scss",
- "iconBgFilePath": "src/styles/_icon_colors.scss",
"queryPath": "./src/queries",
"templatesPath": "./src/components/templates",
"templates": [
diff --git a/src/styles/_icon_colors.scss b/src/styles/_icon_colors.scss
deleted file mode 100644
index 11ddd26fe..000000000
--- a/src/styles/_icon_colors.scss
+++ /dev/null
@@ -1,46 +0,0 @@
-
- .card-icon.icon-blog, .btn.icon-blog {
- background: #1f253d;
- color: #edf0fc;
- }
-
- .card-icon.icon-js, .btn.icon-js {
- background: #f6d854;
- color: #392f31;
- }
-
- .card-icon.icon-csharp, .btn.icon-csharp {
- background: #672179;
- color: #ffffff;
- }
-
- .card-icon.icon-css, .btn.icon-css {
- background: #3f4de4;
- color: #ffffff;
- }
-
- .card-icon.icon-dart, .btn.icon-dart {
- background: #1b2634;
- color: #ffffff;
- }
-
- .card-icon.icon-golang, .btn.icon-golang {
- background: #5ac9e2;
- color: #000000;
- }
-
- .card-icon.icon-php, .btn.icon-php {
- background: #8b9bd6;
- color: #2a2843;
- }
-
- .card-icon.icon-python, .btn.icon-python {
- background: #3c77a9;
- color: #ffffff;
- }
-
- .card-icon.icon-react, .btn.icon-react {
- background: #282c34;
- color: #61dafb;
- }
-
\ No newline at end of file
diff --git a/src/styles/_icons.scss b/src/styles/_icons.scss
index d736c71fc..19dc12a03 100644
--- a/src/styles/_icons.scss
+++ b/src/styles/_icons.scss
@@ -1,6 +1,6 @@
@font-face {
font-family: "icons";
- src: url("../../assets/icons.woff2?bc96d006b08d44606f3122178a9e0225") format("woff2");
+ src: url("../../assets/icons.woff2?ee05ab874cb7c5179be6f88e879bb65c") format("woff2");
}
.icon:before {
@@ -80,3 +80,43 @@
.icon.icon-twitter:before {
content: "\f116";
}
+
+.card-icon,
+.btn {
+ &.icon-blog {
+ background: #1f253d;
+ color: #edf0fc;
+ }
+ &.icon-js {
+ background: #f6d854;
+ color: #392f31;
+ }
+ &.icon-csharp {
+ background: #672179;
+ color: #ffffff;
+ }
+ &.icon-css {
+ background: #3f4de4;
+ color: #ffffff;
+ }
+ &.icon-dart {
+ background: #1b2634;
+ color: #ffffff;
+ }
+ &.icon-golang {
+ background: #5ac9e2;
+ color: #000000;
+ }
+ &.icon-php {
+ background: #8b9bd6;
+ color: #2a2843;
+ }
+ &.icon-python {
+ background: #3c77a9;
+ color: #ffffff;
+ }
+ &.icon-react {
+ background: #282c34;
+ color: #61dafb;
+ }
+}
diff --git a/src/styles/index.scss b/src/styles/index.scss
index 58d5d477a..97685c0f2 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -1,7 +1,6 @@
@import './fonts';
@import './icons';
@import './global_variables';
-@import './icon_colors';
@import './reset';
@import './code';
@import './anchor';
diff --git a/src/yild/core/actions.js b/src/yild/core/actions.js
index bd26c620b..50d16edd4 100644
--- a/src/yild/core/actions.js
+++ b/src/yild/core/actions.js
@@ -4,7 +4,6 @@ import extractSnippets from '../extractSnippets';
import serveSnippets from '../serveSnippets';
import updateContent from '../updateContent';
import makeIcons from '../makeIcons';
-import makeLangBackgrounds from '../makeLangBackgrounds';
import prepareEnv from '../prepareEnv';
import prepareCacheKey from '../prepareCacheKey';
@@ -46,12 +45,6 @@ const actions = {
step: 0,
matcher: /^-{0,2}i(cons)?$/gi,
},
- 'backgrounds': {
- description: 'generate SCSS styles from the provided icons',
- process: makeLangBackgrounds,
- step: 0,
- matcher: /^-{0,2}b(ackgrounds)?$/gi,
- },
'environment': {
description: `generate environment configuration file\n${format('ENV', 'green', 'bold')} can be one of: (DEVELOPMENT, PRODUCTION)`,
process: prepareEnv,
diff --git a/src/yild/makeIcons/cssTemplate.hbs b/src/yild/makeIcons/cssTemplate.hbs
index f1e46c86b..08c02a5e9 100644
--- a/src/yild/makeIcons/cssTemplate.hbs
+++ b/src/yild/makeIcons/cssTemplate.hbs
@@ -19,3 +19,14 @@
content: "\\{{ this }}";
}
{{/ each }}
+
+{{# each langSelectors }}
+{{this}}{{#if @last}} { {{else}}, {{/if}}
+{{/ each}}
+{{# each langIcons }}
+ &.{{ ../classPrefix }}{{ this.iconName }} {
+ background: {{ this.backColor }};
+ color: {{ this.foreColor }};
+ }
+{{/ each }}
+}
diff --git a/src/yild/makeIcons/index.js b/src/yild/makeIcons/index.js
index 5dcd39eb9..ff1bf2798 100644
--- a/src/yild/makeIcons/index.js
+++ b/src/yild/makeIcons/index.js
@@ -2,7 +2,7 @@ import glob from 'glob';
import fs from 'fs-extra';
import path from 'path';
import webfontsGenerator from 'webfonts-generator';
-import { initAction } from '../core';
+import { initAction, loadContentConfigs } from '../core';
import iconConfig from 'config/icons';
const {
@@ -13,18 +13,21 @@ const {
cssSelector,
cssClassName,
cssClassPrefix,
+ cssLanguageSelectors,
} = iconConfig;
/**
* Generate a woff2 fle with the icon font and CSS styles to go with it.
*/
const makeIcons = () => {
- const [boundLog, , inPath, outPath, cssPath] = initAction('makeIcons', [
+ const [boundLog, , inPath, contentPath, outPath, cssPath] = initAction('makeIcons', [
['paths', 'rawIconPath'],
+ ['paths', 'rawContentPath'],
['paths', 'rawAssetPath'],
['paths', 'iconFontPath'],
]);
const files = glob.sync(`${inPath}`);
+ const configs = loadContentConfigs(contentPath, boundLog);
boundLog(`Generating icon font and styles from ${files.length} files...`, 'info');
const config = {
@@ -41,6 +44,10 @@ const makeIcons = () => {
baseSelector: cssSelector,
baseClassNames: cssClassName,
classPrefix: cssClassPrefix,
+ langSelectors: cssLanguageSelectors,
+ langIcons: configs
+ .map(cfg => cfg.theme)
+ .filter(Boolean),
},
};
diff --git a/src/yild/makeLangBackgrounds/index.js b/src/yild/makeLangBackgrounds/index.js
deleted file mode 100644
index 42ef82765..000000000
--- a/src/yild/makeLangBackgrounds/index.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import fs from 'fs-extra';
-import path from 'path';
-import { initAction, loadContentConfigs } from '../core';
-
-/**
- * Generate a SCSS file with the language background styles.
- */
-const makeLanguageBgs = async() => {
- const [boundLog, , inPath, outPath] = initAction('makeLanguageBgs', [
- ['paths', 'rawContentPath'], ['paths', 'iconBgFilePath'],
- ]);
- boundLog('Generating language background styles from config...', 'info');
-
- const configs = loadContentConfigs(inPath, boundLog);
- boundLog(`Generating SCSS code from configuration files`, 'success');
- const scss = configs
- .map(cfg => cfg.theme)
- .filter(Boolean)
- .reduce((acc, cfg) => `${acc}
- .card-icon.icon-${cfg.iconName}, .btn.icon-${cfg.iconName} {
- background: ${cfg.backColor};
- color: ${cfg.foreColor};
- }
- `, '');
-
- boundLog(`Writing SCSS code to ${path.resolve(outPath)}`, 'info');
- await fs.writeFile(outPath, scss);
- boundLog('Generating language background styles complete', 'success');
-
- return;
-};
-
-export default makeLanguageBgs;
From a46e5b25c9e9e7d43a54a36a87d06b0027b17a93 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Tue, 25 Aug 2020 23:40:32 +0300
Subject: [PATCH 04/39] Move individual snippet parsing to own function
Allow each snippet to be parsed as a single unit, decouple
from readSnippets, allowing individual rebuilds.
---
src/yild/extractSnippets/parseSnippets.js | 233 ++++++++++++----------
1 file changed, 127 insertions(+), 106 deletions(-)
diff --git a/src/yild/extractSnippets/parseSnippets.js b/src/yild/extractSnippets/parseSnippets.js
index 21237aa38..ded53e1dd 100644
--- a/src/yild/extractSnippets/parseSnippets.js
+++ b/src/yild/extractSnippets/parseSnippets.js
@@ -161,6 +161,131 @@ export const getTags = tagStr => [...new Set(tagStr.split(','))];
*/
export const getId = (snippetFilename, sourceDir) => `${sourceDir}/${snippetFilename.slice(0, -3)}`;
+export const parseSnippet = async(
+ snippetsPath, snippet, {
+ sourceDir, commonData, slugPrefix, repoUrlPrefix, assetPath, langData, language,
+ isCssSnippet, isBlogSnippet, hasOptionalLanguage, languages, icon, biasPenaltyMultiplier,
+ }
+) => {
+ let data, gitMetadata;
+ await Promise.all([
+ getData(snippetsPath, snippet),
+ getGitMetadata(snippet, snippetsPath),
+ ]).then(values => {
+ data = values[0];
+ gitMetadata = values[1];
+ });
+ const tags = getTags(data.attributes.tags);
+ const text = getTextualContent(data.body);
+ const [ code, rawCode ] = isBlogSnippet
+ ? [ null, [ ] ]
+ : getCodeBlocks(data.body, {
+ isCssSnippet,
+ hasOptionalLanguage,
+ languages,
+ snippetName: snippet.slice(0, -3),
+ });
+ const type = isBlogSnippet ? `blog.${data.attributes.type}` : 'snippet';
+
+ let excerpt, cover, shortSliceIndex, authorsData, langIcon, shortText;
+
+ if (isBlogSnippet) {
+ excerpt = data.attributes.excerpt;
+ cover = `${assetPath}${data.attributes.cover}`;
+ shortSliceIndex = text.indexOf('\n\n') <= 180
+ ? text.indexOf('\n\n')
+ : text.indexOf(' ', 160);
+ shortText = excerpt && excerpt.trim().length !== 0
+ ? excerpt
+ : `${text.slice(0, shortSliceIndex)}...`;
+ authorsData = getTags(data.attributes.authors).map(a => authors[a]);
+ langIcon = langData.find(l => tags.includes(l.language));
+ } else
+ shortText = text.slice(0, text.indexOf('\n\n'));
+
+ const html = parseMarkdown(
+ {
+ texts: {
+ fullDescription: isBlogSnippet ? data.body : text,
+ description: shortText,
+ },
+ codeBlocks: rawCode,
+ }, {
+ isBlog: isBlogSnippet,
+ type,
+ assetPath,
+ }
+ );
+
+ const snippetData = {
+ ...commonData,
+ id: getId(snippet, sourceDir),
+ title: data.attributes.title,
+ type,
+ tags: {
+ all: tags,
+ primary: tags[0],
+ },
+ code,
+ expertise: isBlogSnippet ? 'blog' : determineExpertiseFromTags(tags),
+ text: {
+ full: isBlogSnippet ? data.body : text,
+ short: shortText,
+ },
+ cover,
+ authors: authorsData,
+ icon: langIcon ? langIcon.icon : icon,
+ searchTokens: uniqueElements(
+ isBlogSnippet ? [
+ ...stripExpertiseFromTags(tags),
+ ...tokenizeSnippet(`${shortText} ${data.attributes.title}`),
+ ].map(v => v.toLowerCase()) : [
+ data.attributes.title,
+ language.short,
+ language.long,
+ ...stripExpertiseFromTags(tags),
+ ...tokenizeSnippet(shortText),
+ ].map(v => v.toLowerCase())
+ ).join(' '),
+ html,
+ ...gitMetadata,
+ slug: `/${slugPrefix}${convertToSeoSlug(snippet.slice(0, -3))}`,
+ url: `${repoUrlPrefix}/${snippet}`,
+ };
+
+ snippetData.ranking = rankSnippet({
+ ...snippetData,
+ language: commonData.language,
+ biasPenaltyMultiplier: biasPenaltyMultiplier
+ ? biasPenaltyMultiplier
+ : 1.0,
+ });
+
+ return snippetData;
+};
+
+export const getParams = (config, langData, assetPath) => {
+ const isCssSnippet = config.dirName === '30css';
+ const isBlogSnippet = config.isBlog;
+ const hasOptionalLanguage = !isCssSnippet && !isBlogSnippet && config.optionalLanguage && config.optionalLanguage.short;
+ const languages = isBlogSnippet ? [] : [
+ config.language.short,
+ isCssSnippet ? config.secondLanguage.short : null,
+ hasOptionalLanguage || isCssSnippet ? config.optionalLanguage.short : null,
+ ].filter(Boolean).join('|');
+ const icon = config.theme ? config.theme.iconName : null;
+ return {
+ sourceDir: `${config.dirName}/${config.snippetPath}`,
+ commonData: config.commonData,
+ slugPrefix: config.slugPrefix,
+ language: config.language,
+ biasPenaltyMultiplier: config.biasPenaltyMultiplier,
+ repoUrlPrefix: config.repoUrlPrefix,
+ isCssSnippet, isBlogSnippet, hasOptionalLanguage, languages, icon,
+ langData, assetPath,
+ };
+};
+
/**
* Synchronously read all snippets and sort them as necessary.
* The sorting is case-insensitive.
@@ -173,116 +298,12 @@ export const getId = (snippetFilename, sourceDir) => `${sourceDir}/${snippetFile
*/
export const readSnippets = async(snippetsPath, assetPath, config, langData, boundLog) => {
const snippetFilenames = getFilesInDir(snippetsPath, boundLog);
- const sourceDir = `${config.dirName}/${config.snippetPath}`;
- const { commonData, slugPrefix, repoUrlPrefix } = config;
-
- const isCssSnippet = config.dirName === '30css';
- const isBlogSnippet = config.isBlog;
- const hasOptionalLanguage = !isCssSnippet && !isBlogSnippet && config.optionalLanguage && config.optionalLanguage.short;
- const languages = isBlogSnippet ? [] : [
- config.language.short,
- isCssSnippet ? config.secondLanguage.short : null,
- hasOptionalLanguage || isCssSnippet ? config.optionalLanguage.short : null,
- ].filter(Boolean).join('|');
- const icon = config.theme ? config.theme.iconName : null;
+ const params = getParams(config, langData, assetPath);
let snippets = [];
try {
for (let snippet of snippetFilenames) {
- let data, gitMetadata;
- await Promise.all([
- getData(snippetsPath, snippet),
- getGitMetadata(snippet, snippetsPath),
- ]).then(values => {
- data = values[0];
- gitMetadata = values[1];
- });
- const tags = getTags(data.attributes.tags);
- const text = getTextualContent(data.body);
- const [ code, rawCode ] = isBlogSnippet
- ? [ null, [ ] ]
- : getCodeBlocks(data.body, {
- isCssSnippet,
- hasOptionalLanguage,
- languages,
- snippetName: snippet.slice(0, -3),
- });
- const type = isBlogSnippet ? `blog.${data.attributes.type}` : 'snippet';
-
- let excerpt, cover, shortSliceIndex, authorsData, langIcon, shortText;
-
- if (isBlogSnippet) {
- excerpt = data.attributes.excerpt;
- cover = `${assetPath}${data.attributes.cover}`;
- shortSliceIndex = text.indexOf('\n\n') <= 180
- ? text.indexOf('\n\n')
- : text.indexOf(' ', 160);
- shortText = excerpt && excerpt.trim().length !== 0
- ? excerpt
- : `${text.slice(0, shortSliceIndex)}...`;
- authorsData = getTags(data.attributes.authors).map(a => authors[a]);
- langIcon = langData.find(l => tags.includes(l.language));
- } else
- shortText = text.slice(0, text.indexOf('\n\n'));
-
- const html = parseMarkdown(
- {
- texts: {
- fullDescription: isBlogSnippet ? data.body : text,
- description: shortText,
- },
- codeBlocks: rawCode,
- }, {
- isBlog: isBlogSnippet,
- type,
- assetPath,
- }
- );
-
- const snippetData = {
- ...commonData,
- id: getId(snippet, sourceDir),
- title: data.attributes.title,
- type,
- tags: {
- all: tags,
- primary: tags[0],
- },
- code,
- expertise: isBlogSnippet ? 'blog' : determineExpertiseFromTags(tags),
- text: {
- full: isBlogSnippet ? data.body : text,
- short: shortText,
- },
- cover,
- authors: authorsData,
- icon: langIcon ? langIcon.icon : icon,
- searchTokens: uniqueElements(
- isBlogSnippet ? [
- ...stripExpertiseFromTags(tags),
- ...tokenizeSnippet(`${shortText} ${data.attributes.title}`),
- ].map(v => v.toLowerCase()) : [
- data.attributes.title,
- config.language.short,
- config.language.long,
- ...stripExpertiseFromTags(tags),
- ...tokenizeSnippet(shortText),
- ].map(v => v.toLowerCase())
- ).join(' '),
- html,
- ...gitMetadata,
- slug: `/${slugPrefix}${convertToSeoSlug(snippet.slice(0, -3))}`,
- url: `${repoUrlPrefix}/${snippet}`,
- };
-
- snippetData.ranking = rankSnippet({
- ...snippetData,
- language: commonData.language,
- biasPenaltyMultiplier: config.biasPenaltyMultiplier
- ? config.biasPenaltyMultiplier
- : 1.0,
- });
-
+ const snippetData = await parseSnippet(snippetsPath, snippet, params);
snippets.push(snippetData);
}
} catch (err) {
From 32a53dd3571a008028a00d5f72b0e150431319bb Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 00:12:17 +0300
Subject: [PATCH 05/39] Fix a bug with recommendation ranking mutability
recommendationRanking mutated the snippet object,
allowing for previous recommendations to rank in certain
cases.
---
src/engines/recommendationEngine.js | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/engines/recommendationEngine.js b/src/engines/recommendationEngine.js
index 4dcdeb1e9..74ef1231a 100644
--- a/src/engines/recommendationEngine.js
+++ b/src/engines/recommendationEngine.js
@@ -27,10 +27,9 @@ const determineRecommendedSnippets = (snippetNodes, snippetContext) => {
return snippetNodes
.map(v => {
+ v.recommendationRanking = 0;
// Filter out any nodes with the same id (this very snippet)
- if(v.id === snippetContext.id)
- v.recommendationRanking = 0;
- else {
+ if(v.id !== snippetContext.id) {
// Determine score for language:
// * Same language, as language = 100% of language score
// * Same language, but as a tag = 25% of language score
From 6f4e2cb71816da8b80bed9cf2cfd78bade32b6b1 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 00:14:24 +0300
Subject: [PATCH 06/39] Trim down parsed snippets in memory, write data
Write individual snippet data in its own file, minimize
amount of data stored in memory.
---
src/yild/extractSnippets/extract.js | 2 +-
src/yild/extractSnippets/parseSnippets.js | 42 +++++++++++++++++++----
2 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/src/yild/extractSnippets/extract.js b/src/yild/extractSnippets/extract.js
index 5ce6574fd..21131ae20 100644
--- a/src/yild/extractSnippets/extract.js
+++ b/src/yild/extractSnippets/extract.js
@@ -27,7 +27,7 @@ const extract = (configs, langData, parentLog) => configs.map(cfg => {
boundLog(`Extracting snippets from ${snippetsPath}`, 'info');
return new Promise((resolve, reject) =>
- parseSnippets(snippetsPath, assetPath, {...cfg, commonData, slugPrefix, repoUrlPrefix}, langData, boundLog)
+ parseSnippets(snippetsPath, assetPath, contentOutDir, {...cfg, commonData, slugPrefix, repoUrlPrefix}, langData, boundLog)
.then(snippetsArray => {
const completeData = {
data: snippetsArray,
diff --git a/src/yild/extractSnippets/parseSnippets.js b/src/yild/extractSnippets/parseSnippets.js
index ded53e1dd..5e4fe7ec8 100644
--- a/src/yild/extractSnippets/parseSnippets.js
+++ b/src/yild/extractSnippets/parseSnippets.js
@@ -163,8 +163,9 @@ export const getId = (snippetFilename, sourceDir) => `${sourceDir}/${snippetFile
export const parseSnippet = async(
snippetsPath, snippet, {
- sourceDir, commonData, slugPrefix, repoUrlPrefix, assetPath, langData, language,
- isCssSnippet, isBlogSnippet, hasOptionalLanguage, languages, icon, biasPenaltyMultiplier,
+ sourceDir, commonData, slugPrefix, repoUrlPrefix, assetPath, outPath,
+ langData, language, isCssSnippet, isBlogSnippet, hasOptionalLanguage,
+ languages, icon, biasPenaltyMultiplier,
}
) => {
let data, gitMetadata;
@@ -261,10 +262,36 @@ export const parseSnippet = async(
: 1.0,
});
- return snippetData;
+ const outDir = `${outPath}/${snippetData.slug.slice(1)}`;
+ fs.ensureDirSync(outDir);
+ fs.writeFileSync(
+ `${outDir}/snippet.json`,
+ JSON.stringify(snippetData, null, 2)
+ );
+
+ const trimmedData = {
+ id: snippetData.id,
+ tags: snippetData.tags,
+ language: {
+ long: snippetData.language.long,
+ short: snippetData.language.short,
+ },
+ searchTokens: snippetData.searchTokens,
+ ranking: snippetData.ranking,
+ blog: snippetData.blog,
+ title: snippetData.title,
+ expertise: snippetData.expertise,
+ icon: snippetData.icon,
+ slug: snippetData.slug,
+ html: {
+ description: snippetData.html.description,
+ },
+ };
+
+ return trimmedData;
};
-export const getParams = (config, langData, assetPath) => {
+export const getParams = (config, langData, assetPath, outPath) => {
const isCssSnippet = config.dirName === '30css';
const isBlogSnippet = config.isBlog;
const hasOptionalLanguage = !isCssSnippet && !isBlogSnippet && config.optionalLanguage && config.optionalLanguage.short;
@@ -282,7 +309,7 @@ export const getParams = (config, langData, assetPath) => {
biasPenaltyMultiplier: config.biasPenaltyMultiplier,
repoUrlPrefix: config.repoUrlPrefix,
isCssSnippet, isBlogSnippet, hasOptionalLanguage, languages, icon,
- langData, assetPath,
+ langData, assetPath, outPath,
};
};
@@ -291,14 +318,15 @@ export const getParams = (config, langData, assetPath) => {
* The sorting is case-insensitive.
* @param {string} snippetsPath - The path of the snippets directory.
* @param {string} assetPath - The public path of the assets directory.
+ * @param {string} outPath - The output path of the snippets directory.
* @param {object} config - The project's enriched configuration
* (containing the spread config, commonData and prefixes).
* @param {array} langData - An array of `(language, icon)` tuples.
* @param {function} boundLog - A bound logger.log function.
*/
-export const readSnippets = async(snippetsPath, assetPath, config, langData, boundLog) => {
+export const readSnippets = async(snippetsPath, assetPath, outPath, config, langData, boundLog) => {
const snippetFilenames = getFilesInDir(snippetsPath, boundLog);
- const params = getParams(config, langData, assetPath);
+ const params = getParams(config, langData, assetPath, outPath);
let snippets = [];
try {
From d54fcbceaf2edd28e45a4aaf0ae08d70336f9f16 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 00:14:46 +0300
Subject: [PATCH 07/39] Post-process snippet recommendations
Rewrite system to output to individual files.
---
src/yild/extractSnippets/extract.js | 3 +-
src/yild/extractSnippets/postProcess.js | 80 +++++++++++--------------
2 files changed, 36 insertions(+), 47 deletions(-)
diff --git a/src/yild/extractSnippets/extract.js b/src/yild/extractSnippets/extract.js
index 21131ae20..d9fe385d9 100644
--- a/src/yild/extractSnippets/extract.js
+++ b/src/yild/extractSnippets/extract.js
@@ -12,7 +12,6 @@ const extract = (configs, langData, parentLog) => configs.map(cfg => {
const snippetsPath = `${contentDir}/sources/${cfg.dirName}/${cfg.snippetPath}`;
const assetPath = `/${assetDir}/`;
- const outputJson = `${contentOutDir}/${cfg.dirName}.json`;
const slugPrefix = `${cfg.slug}/s`;
const repoUrlPrefix = `${cfg.repoUrl}/blob/master/${cfg.snippetPath}`;
const isBlog = !!cfg.isBlog;
@@ -46,7 +45,7 @@ const extract = (configs, langData, parentLog) => configs.map(cfg => {
};
boundLog(`Finished extracting ${snippetsPath}`, 'success');
resolve({
- outputFile: outputJson,
+ snippetsPath,
data: completeData,
});
})
diff --git a/src/yild/extractSnippets/postProcess.js b/src/yild/extractSnippets/postProcess.js
index 129126e2c..952f0f300 100644
--- a/src/yild/extractSnippets/postProcess.js
+++ b/src/yild/extractSnippets/postProcess.js
@@ -4,51 +4,41 @@ import recommendationEngine from 'engines/recommendationEngine';
const postProcess = (allData, allSnippetData, parentLog) => {
const boundLog = parentLog.rebind('postProcess');
- return allData.map(({ outputFile, data }) => new Promise((resolve, reject) => {
- boundLog(`Post-processing snippets for ${outputFile}`, 'info');
- const outputData = {
- data: data.data.map(snippet => {
- const recommendedSnippets = recommendationEngine(allSnippetData, snippet)
- .map(({
- id, title, expertise, tags, language,
- icon, html, slug, searchTokens,
- recommendationRanking,
- }) => ({
- id, title, expertise, icon, slug, searchTokens,
- recommendationRanking: +recommendationRanking,
- html: {
- description: html.description,
- },
- tags: {
- primary: tags.primary,
- },
- language: {
- short: language.short,
- long: language.long,
- },
- }));
- return {
- ...snippet,
- recommendedSnippets,
- };
- }),
- meta: data.meta,
- };
- fs.writeFile(
- outputFile,
- JSON.stringify(outputData, null, 2),
- err => {
- if (err) {
- boundLog(`Encountered an error while writing ${outputFile}`, 'error');
- boundLog(`${err}`, 'error');
- reject(err);
- } else {
- boundLog(`Finished writing ${outputFile}`, 'success');
- resolve();
- }
- }
- );
- }));
+ return allData.map(async({ snippetsPath, data }) => {
+ const {
+ contentPath: contentOutDir,
+ } = global._yild_instance.config.paths;
+ boundLog(`Post-processing snippets for ${snippetsPath}`, 'info');
+
+ for (let snippet of data.data) {
+ const recommendedSnippets = recommendationEngine(allSnippetData, snippet)
+ .map(({
+ id, title, expertise, tags, language,
+ icon, html, slug, searchTokens,
+ recommendationRanking,
+ }) => ({
+ id, title, expertise, icon, slug, searchTokens,
+ recommendationRanking: +recommendationRanking,
+ html: {
+ description: html.description,
+ },
+ tags: {
+ primary: tags.primary,
+ },
+ language: {
+ short: language.short,
+ long: language.long,
+ },
+ }));
+
+ const outDir = `${contentOutDir}/${snippet.slug.slice(1)}`;
+ fs.ensureDirSync(outDir);
+ await fs.writeFile(
+ `${outDir}/recommendations.json`,
+ JSON.stringify(recommendedSnippets, null, 2)
+ );
+ }
+ });
};
export default postProcess;
From 054f6f1841f22b9cf0b1a78d93ecb81cbaa01e87 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 00:45:37 +0300
Subject: [PATCH 08/39] Transform snippet data from yild
---
src/yild/extractSnippets/parseSnippets.js | 4 ++--
src/yild/extractSnippets/postProcess.js | 23 ++++-------------------
2 files changed, 6 insertions(+), 21 deletions(-)
diff --git a/src/yild/extractSnippets/parseSnippets.js b/src/yild/extractSnippets/parseSnippets.js
index 5e4fe7ec8..b247b5c08 100644
--- a/src/yild/extractSnippets/parseSnippets.js
+++ b/src/yild/extractSnippets/parseSnippets.js
@@ -5,7 +5,7 @@ import frontmatter from 'front-matter';
import { exec } from 'child_process';
import tokenizeSnippet from 'engines/searchIndexingEngine';
import { convertToSeoSlug, uniqueElements } from 'utils';
-import { determineExpertiseFromTags, stripExpertiseFromTags } from 'build/transformers';
+import { determineExpertiseFromTags, stripExpertiseFromTags, transformSnippetContext } from 'build/transformers';
import rankSnippet from 'engines/rankingEngine';
import parseMarkdown from './parseMarkdown';
// TODO: Consider parsing this via a new parser or similar
@@ -266,7 +266,7 @@ export const parseSnippet = async(
fs.ensureDirSync(outDir);
fs.writeFileSync(
`${outDir}/snippet.json`,
- JSON.stringify(snippetData, null, 2)
+ JSON.stringify(transformSnippetContext(snippetData), null, 2)
);
const trimmedData = {
diff --git a/src/yild/extractSnippets/postProcess.js b/src/yild/extractSnippets/postProcess.js
index 952f0f300..c307e2bc2 100644
--- a/src/yild/extractSnippets/postProcess.js
+++ b/src/yild/extractSnippets/postProcess.js
@@ -1,5 +1,6 @@
import fs from 'fs-extra';
import recommendationEngine from 'engines/recommendationEngine';
+import { transformSnippetIndex } from 'build/transformers';
const postProcess = (allData, allSnippetData, parentLog) => {
const boundLog = parentLog.rebind('postProcess');
@@ -11,25 +12,9 @@ const postProcess = (allData, allSnippetData, parentLog) => {
boundLog(`Post-processing snippets for ${snippetsPath}`, 'info');
for (let snippet of data.data) {
- const recommendedSnippets = recommendationEngine(allSnippetData, snippet)
- .map(({
- id, title, expertise, tags, language,
- icon, html, slug, searchTokens,
- recommendationRanking,
- }) => ({
- id, title, expertise, icon, slug, searchTokens,
- recommendationRanking: +recommendationRanking,
- html: {
- description: html.description,
- },
- tags: {
- primary: tags.primary,
- },
- language: {
- short: language.short,
- long: language.long,
- },
- }));
+ const recommendedSnippets = transformSnippetIndex(
+ recommendationEngine(allSnippetData, snippet).map(v => ( { node: v }))
+ );
const outDir = `${contentOutDir}/${snippet.slug.slice(1)}`;
fs.ensureDirSync(outDir);
From cfa6b16141457d63ae7e947bddf57e2bd8ffbc6c Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 12:10:45 +0300
Subject: [PATCH 09/39] Add cardTemplate to content configs
---
content/configs/30blog.json | 3 ++-
content/configs/30css.json | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/content/configs/30blog.json b/content/configs/30blog.json
index 6857a1b6a..a2957ba5e 100644
--- a/content/configs/30blog.json
+++ b/content/configs/30blog.json
@@ -19,5 +19,6 @@
"images": {
"name": "blog_images",
"path": "blog_images"
- }
+ },
+ "cardTemplate": "BlogSnippetCard"
}
diff --git a/content/configs/30css.json b/content/configs/30css.json
index 66668b354..68e0d0f51 100644
--- a/content/configs/30css.json
+++ b/content/configs/30css.json
@@ -26,5 +26,6 @@
"foreColor": "#ffffff",
"iconName": "css"
},
- "biasPenaltyMultiplier": 1.05
+ "biasPenaltyMultiplier": 1.05,
+ "cardTemplate": "CssSnippetCard"
}
From 1fba87d133879c5b6095e263b301d80c43ac0b7a Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 12:11:05 +0300
Subject: [PATCH 10/39] Write snippet metadata to JSON
---
src/yild/extractSnippets/extract.js | 1 +
src/yild/extractSnippets/parseSnippets.js | 21 ++++++++++++++++++---
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/src/yild/extractSnippets/extract.js b/src/yild/extractSnippets/extract.js
index d9fe385d9..291bdb245 100644
--- a/src/yild/extractSnippets/extract.js
+++ b/src/yild/extractSnippets/extract.js
@@ -23,6 +23,7 @@ const extract = (configs, langData, parentLog) => configs.map(cfg => {
if (cfg.secondLanguage) otherLanguages.push(cfg.secondLanguage);
if (cfg.optionalLanguage) otherLanguages.push(cfg.optionalLanguage);
if (otherLanguages.length) commonData.language.otherLanguages = otherLanguages;
+ if (!cfg.cardTemplate) cfg.cardTemplate = 'StandardSnippetCard';
boundLog(`Extracting snippets from ${snippetsPath}`, 'info');
return new Promise((resolve, reject) =>
diff --git a/src/yild/extractSnippets/parseSnippets.js b/src/yild/extractSnippets/parseSnippets.js
index b247b5c08..e8807c3c2 100644
--- a/src/yild/extractSnippets/parseSnippets.js
+++ b/src/yild/extractSnippets/parseSnippets.js
@@ -5,7 +5,13 @@ import frontmatter from 'front-matter';
import { exec } from 'child_process';
import tokenizeSnippet from 'engines/searchIndexingEngine';
import { convertToSeoSlug, uniqueElements } from 'utils';
-import { determineExpertiseFromTags, stripExpertiseFromTags, transformSnippetContext } from 'build/transformers';
+import {
+ determineExpertiseFromTags,
+ stripExpertiseFromTags,
+ transformSnippetContext,
+ transformBreadcrumbs,
+ transformSnippetDescription
+} from 'build/transformers';
import rankSnippet from 'engines/rankingEngine';
import parseMarkdown from './parseMarkdown';
// TODO: Consider parsing this via a new parser or similar
@@ -165,7 +171,7 @@ export const parseSnippet = async(
snippetsPath, snippet, {
sourceDir, commonData, slugPrefix, repoUrlPrefix, assetPath, outPath,
langData, language, isCssSnippet, isBlogSnippet, hasOptionalLanguage,
- languages, icon, biasPenaltyMultiplier,
+ languages, icon, biasPenaltyMultiplier, cardTemplate,
}
) => {
let data, gitMetadata;
@@ -266,7 +272,15 @@ export const parseSnippet = async(
fs.ensureDirSync(outDir);
fs.writeFileSync(
`${outDir}/snippet.json`,
- JSON.stringify(transformSnippetContext(snippetData), null, 2)
+ JSON.stringify(transformSnippetContext(snippetData, cardTemplate), null, 2)
+ );
+ fs.writeFileSync(
+ `${outDir}/metadata.json`,
+ JSON.stringify({
+ cardTemplate,
+ breadcrumbs: transformBreadcrumbs(snippetData, cardTemplate),
+ pageDescription: transformSnippetDescription(snippetData, cardTemplate),
+ }, null, 2)
);
const trimmedData = {
@@ -306,6 +320,7 @@ export const getParams = (config, langData, assetPath, outPath) => {
commonData: config.commonData,
slugPrefix: config.slugPrefix,
language: config.language,
+ cardTemplate: config.cardTemplate,
biasPenaltyMultiplier: config.biasPenaltyMultiplier,
repoUrlPrefix: config.repoUrlPrefix,
isCssSnippet, isBlogSnippet, hasOptionalLanguage, languages, icon,
From daee9f4727d652fc09ad5f83261e37090c51de62 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 14:28:06 +0300
Subject: [PATCH 11/39] Extract listing pages data from yild
Mirror logic previously in createListingPages.
---
src/yild/extractSnippets/postProcess.js | 244 ++++++++++++++++++++++++
1 file changed, 244 insertions(+)
diff --git a/src/yild/extractSnippets/postProcess.js b/src/yild/extractSnippets/postProcess.js
index c307e2bc2..080e58c7b 100644
--- a/src/yild/extractSnippets/postProcess.js
+++ b/src/yild/extractSnippets/postProcess.js
@@ -1,10 +1,254 @@
import fs from 'fs-extra';
import recommendationEngine from 'engines/recommendationEngine';
import { transformSnippetIndex } from 'build/transformers';
+import { chunk } from 'utils';
+import EXPERTISE_LEVELS from 'config/expertise';
+import literals from 'lang/en/listing';
+
+const ORDERS_MAP = {
+ 'p': literals.orders.popularity,
+ 'a': literals.orders.alphabetical,
+ 'e': literals.orders.expertise,
+};
+
+const CARDS_PER_PAGE = 40;
+
+const compileListingPages = (
+ indexedChunks,
+ context,
+ baseUrl,
+ slugOrderingSegment,
+ ordersList
+) => {
+ const {
+ contentPath: contentOutDir,
+ } = global._yild_instance.config.paths;
+
+ indexedChunks.forEach((chunk, i, chunks) => {
+ const outDir = `${contentOutDir}${baseUrl}/${slugOrderingSegment}/${i + 1}`;
+ fs.ensureDirSync(outDir);
+
+ fs.writeFileSync(
+ `${outDir}/snippetList.json`,
+ JSON.stringify(chunk, null, 2)
+ );
+ fs.writeFileSync(
+ `${outDir}/metadata.json`,
+ JSON.stringify({
+ isMainListing:
+ context.listingType === 'main' &&
+ slugOrderingSegment === 'p' &&
+ i === 0,
+ paginator: {
+ pageNumber: i + 1,
+ totalPages: chunks.length,
+ baseUrl,
+ slugOrderingSegment,
+ },
+ sorter: {
+ orders: ordersList.map(order => (
+ {
+ url: `${baseUrl}/${order}/1`,
+ title: ORDERS_MAP[order],
+ }
+ )),
+ selectedOrder: ORDERS_MAP[slugOrderingSegment],
+ },
+ ...context,
+ }, null, 2)
+ );
+ });
+};
+
+const compileListingPagesWithOrderOptions = (
+ context,
+ baseUrl,
+ orders,
+ chunks,
+ contextCustomizer = () => ({})
+) => {
+ orders.forEach((order, i) => {
+ compileListingPages(
+ chunks[i],
+ { ...context, ...contextCustomizer(order, i)},
+ baseUrl,
+ order,
+ orders
+ );
+ });
+};
+
+const compileListingData = (snippetIndex, listingMetas) => {
+ // 1. Create listing pages for the main listing:
+ // Tranform and chunk data for popularity, alphabetical and expertise ordering
+ const transformedIndex = transformSnippetIndex(
+ snippetIndex.map(v => ( { node: v }))
+ );
+ const popularChunks = chunk(transformedIndex, CARDS_PER_PAGE);
+ const alphabeticalChunks = chunk(transformedIndex.sort((a, b) =>
+ a.title.localeCompare(b.title)
+ ), CARDS_PER_PAGE);
+ const expertiseChunks = chunk(transformedIndex.sort((a, b) =>
+ a.expertise === b.expertise ? a.title.localeCompare(b.title) :
+ !a.expertise ? 1 : !b.expertise ? -1 :
+ EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
+ ), CARDS_PER_PAGE);
+ // Create main listing sublinks and customization method for context
+ const mainListingSublinks = listingMetas
+ .map(v => v.featured > 0 ? v : {...v, featured: 500 })
+ .sort((a, b) => a.featured === b.featured ? a.name - b.name : a.featured - b.featured);
+ const mainContextCustomizer = order => {
+ return {
+ listingSublinks: mainListingSublinks
+ .map(l => ({
+ ...l,
+ url: l.url.replace('/p/1', `/${order}/1`),
+ })),
+ };
+ };
+ // Create the listing pages with the order options provided
+ compileListingPagesWithOrderOptions(
+ {
+ listingName: literals.snippetList,
+ listingTitle: literals.snippetList,
+ listingType: 'main',
+ listingSublinks: mainListingSublinks,
+ pageDescription: literals.pageDescription('main', {
+ snippetCount: transformedIndex.length,
+ }),
+ },
+ '/list',
+ ['p', 'a', 'e'],
+ [popularChunks, alphabeticalChunks, expertiseChunks],
+ mainContextCustomizer
+ );
+
+ // 2. Create listing pages for the language listings
+ listingMetas.forEach(listingMeta => {
+ // Determine slug prefix and relevant information, create chunks from data for
+ // each of the ordering options
+ const slugPrefix = listingMeta.slugPrefix;
+ const snippetIndexName = snippetIndex
+ .find(s => s.slug.startsWith(`${slugPrefix}`)).language.long || '';
+ const snippetIndexSlugData = snippetIndex.filter(s =>
+ s.slug.startsWith(`${slugPrefix}`) ||
+ (s.blog && s.tags.all.find(t => t.toLowerCase() === snippetIndexName.toLowerCase()))
+ );
+ const transformedSlugChunks = transformSnippetIndex(
+ snippetIndexSlugData.map(v => ( { node: v }))
+ );
+ const popularSlugChunks = chunk(transformedSlugChunks, CARDS_PER_PAGE);
+ const alphabeticalSlugChunks = chunk(transformedSlugChunks.sort((a, b) =>
+ a.title.localeCompare(b.title)
+ ), CARDS_PER_PAGE);
+ const expertiseSlugChunks = chunk(transformedSlugChunks.sort((a, b) =>
+ a.expertise === b.expertise ? a.title.localeCompare(b.title) :
+ !a.expertise ? 1 : !b.expertise ? -1 :
+ EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
+ ), CARDS_PER_PAGE);
+ // Determine tag prefixes for the listing
+ const snippetIndexTagPrefixes = listingMeta.tags;
+ const slugContextCustomizer = order => {
+ return {
+ listingSublinks: listingMeta.blog ? [] : [
+ {
+ url: `${slugPrefix}/${order}/1`,
+ name: literals.tag('all'),
+ selected: true,
+ },
+ ...listingMeta.tags
+ .map(tag => ({
+ url: `${slugPrefix}/t/${tag}/${order}/1`,
+ name: literals.tag(tag),
+ })),
+ ],
+ };
+ };
+ // Create the listing pages with the order options provided
+ compileListingPagesWithOrderOptions(
+ {
+ listingName: listingMeta.blog ? literals.blog : literals.codelang(snippetIndexName),
+ listingTitle: listingMeta.blog ? literals.blog : literals.codelang(snippetIndexName),
+ listingType: listingMeta.blog ? 'blog' : 'language',
+ pageDescription: literals.pageDescription(listingMeta.blog ? 'blog' : 'language', {
+ snippetCount: snippetIndexSlugData.length,
+ listingLanguage: listingMeta.blog ? 'blog' : snippetIndexName,
+ }),
+ },
+ `${slugPrefix}`,
+ ['p', 'a', 'e'],
+ [popularSlugChunks, alphabeticalSlugChunks, expertiseSlugChunks],
+ slugContextCustomizer
+ );
+
+ // 3. Create listing pages for the tag listings
+ snippetIndexTagPrefixes.forEach(tagPrefix => {
+ // Determine slug prefix and relevant information, create chunks from data
+ // for each of the ordering options
+ const snippetIndexTagData = snippetIndex
+ .filter(s =>
+ s.tags.primary === tagPrefix && s.slug.startsWith(`${slugPrefix}`) ||
+ ( s.blog &&
+ s.tags.all.find(t => t.toLowerCase() === snippetIndexName.toLowerCase()) &&
+ s.tags.all.find(t => t.toLowerCase() === tagPrefix.toLowerCase())
+ )
+ );
+ const transformedTagChunks = transformSnippetIndex(
+ snippetIndexTagData.map(v => ( { node: v }))
+ );
+ const popularTagChunks = chunk(transformedTagChunks, CARDS_PER_PAGE);
+ const alphabeticalTagChunks = chunk(transformedTagChunks.sort((a, b) =>
+ a.title.localeCompare(b.title)
+ ), CARDS_PER_PAGE);
+ const expertiseTagChunks = chunk(transformedTagChunks.sort((a, b) =>
+ a.expertise === b.expertise ? a.title.localeCompare(b.title) :
+ !a.expertise ? 1 : !b.expertise ? -1 :
+ EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
+ ), CARDS_PER_PAGE);
+ const tagContextCustomizer = order => {
+ return {
+ listingSublinks: listingMeta.blog ? [] : [
+ {
+ url: `${slugPrefix}/${order}/1`,
+ name: literals.tag('all'),
+ selected: true,
+ },
+ ...listingMeta.tags
+ .map(tag => ({
+ url: `${slugPrefix}/t/${tag}/${order}/1`,
+ name: literals.tag(tag),
+ })),
+ ].map(tag => ({ ...tag, selected: tag.url.indexOf(`/t/${tagPrefix}/`) !== -1 })),
+ };
+ };
+ // Create the listing pages with the order options provided
+ compileListingPagesWithOrderOptions(
+ {
+ listingName: literals.codelangTag(snippetIndexName, tagPrefix),
+ listingTitle: literals.codelang(snippetIndexName),
+ listingType: 'tag',
+ pageDescription: literals.pageDescription('tag', {
+ snippetCount: snippetIndexSlugData.length,
+ listingLanguage: snippetIndexName,
+ listingTag: tagPrefix,
+ }),
+ },
+ `${slugPrefix}/t/${tagPrefix}`,
+ ['p', 'a', 'e'],
+ [popularTagChunks, alphabeticalTagChunks, expertiseTagChunks],
+ tagContextCustomizer
+ );
+ });
+ });
+};
const postProcess = (allData, allSnippetData, parentLog) => {
const boundLog = parentLog.rebind('postProcess');
+ // Generate listing datas
+ compileListingData(allSnippetData, allData.map(({ data }) => data.meta));
+
+ // Write snippet recommendations
return allData.map(async({ snippetsPath, data }) => {
const {
contentPath: contentOutDir,
From f1504bcd24e9f1aa7c93646591edd05f5a259855 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 19:38:26 +0300
Subject: [PATCH 12/39] Add index.json for all pages
Temporarily generate JSON data for statics.
---
src/yild/extractSnippets/index.js | 42 +++++++++++++++++++++++
src/yild/extractSnippets/parseSnippets.js | 13 ++++++-
src/yild/extractSnippets/postProcess.js | 23 +++++++++----
3 files changed, 71 insertions(+), 7 deletions(-)
diff --git a/src/yild/extractSnippets/index.js b/src/yild/extractSnippets/index.js
index b9c32a1d7..ed35aab8e 100644
--- a/src/yild/extractSnippets/index.js
+++ b/src/yild/extractSnippets/index.js
@@ -2,6 +2,7 @@ import fs from 'fs-extra';
import { initAction, loadContentConfigs } from '../core';
import extract from './extract';
import postProcess from './postProcess';
+import literals from 'lang/en';
const extractSnippets = async() => {
const [boundLog, , inPath, outPath] = initAction('extractSnippets', [
@@ -35,6 +36,47 @@ const extractSnippets = async() => {
.all(postProcess(allData, allSnippetData, boundLog));
boundLog('Snippet post-processing complete', 'success');
+ // TODO: Temporary, let's move this after the next restructure
+ [
+ {
+ slug: '/404',
+ context: {},
+ template: 'NotFoundPage',
+ priority: 0.0,
+ },
+ {
+ slug: '/about',
+ context: {stringLiterals: literals.about},
+ template: 'StaticPage',
+ priority: 0.25,
+ },
+ {
+ slug: '/cookies',
+ context: {stringLiterals: literals.cookies},
+ template: 'StaticPage',
+ priority: 0.25,
+ },
+ {
+ slug: '/settings',
+ context: {stringLiterals: literals.settings},
+ template: 'SettingsPage',
+ priority: 0.01,
+ },
+ ].forEach(p => {
+ const outDir = `${outPath}${p.slug}`;
+ fs.ensureDirSync(outDir);
+ fs.writeFileSync(
+ `${outDir}/index.json`,
+ JSON.stringify({
+ template: p.template,
+ fullRoute: `https://30secondsofcode.org${p.slug}`,
+ relRoute: p.slug,
+ priority: p.priority,
+ }, null, 2)
+ );
+ fs.writeFileSync(`${outDir}/context.json`, JSON.stringify(p.context, null, 2));
+ });
+
return;
};
diff --git a/src/yild/extractSnippets/parseSnippets.js b/src/yild/extractSnippets/parseSnippets.js
index e8807c3c2..97167b679 100644
--- a/src/yild/extractSnippets/parseSnippets.js
+++ b/src/yild/extractSnippets/parseSnippets.js
@@ -270,9 +270,20 @@ export const parseSnippet = async(
const outDir = `${outPath}/${snippetData.slug.slice(1)}`;
fs.ensureDirSync(outDir);
+ fs.writeFileSync(
+ `${outDir}/index.json`,
+ JSON.stringify({
+ template: 'SnippetPage',
+ fullRoute: `https://30secondsofcode.org${snippetData.slug}`,
+ relRoute: `${snippetData.slug}`,
+ priority: (snippetData.ranking * 0.85).toFixed(2),
+ }, null, 2)
+ );
fs.writeFileSync(
`${outDir}/snippet.json`,
- JSON.stringify(transformSnippetContext(snippetData, cardTemplate), null, 2)
+ JSON.stringify({
+ snippet: transformSnippetContext(snippetData, cardTemplate),
+ }, null, 2)
);
fs.writeFileSync(
`${outDir}/metadata.json`,
diff --git a/src/yild/extractSnippets/postProcess.js b/src/yild/extractSnippets/postProcess.js
index 080e58c7b..8c9a616ce 100644
--- a/src/yild/extractSnippets/postProcess.js
+++ b/src/yild/extractSnippets/postProcess.js
@@ -25,20 +25,29 @@ const compileListingPages = (
} = global._yild_instance.config.paths;
indexedChunks.forEach((chunk, i, chunks) => {
+ const isMainListing = context.listingType === 'main' && slugOrderingSegment === 'p' && i === 0;
const outDir = `${contentOutDir}${baseUrl}/${slugOrderingSegment}/${i + 1}`;
fs.ensureDirSync(outDir);
+ fs.writeFileSync(
+ `${outDir}/index.json`,
+ JSON.stringify({
+ template: 'ListingPage',
+ fullRoute: `https://30secondsofcode.org${baseUrl}/${slugOrderingSegment}/${i + 1}`,
+ relRoute: `${baseUrl}/${slugOrderingSegment}/${i + 1}`,
+ priority: isMainListing ? 1.0 : 0.7,
+ }, null, 2)
+ );
fs.writeFileSync(
`${outDir}/snippetList.json`,
- JSON.stringify(chunk, null, 2)
+ JSON.stringify({
+ snippetList: chunk,
+ }, null, 2)
);
fs.writeFileSync(
`${outDir}/metadata.json`,
JSON.stringify({
- isMainListing:
- context.listingType === 'main' &&
- slugOrderingSegment === 'p' &&
- i === 0,
+ isMainListing,
paginator: {
pageNumber: i + 1,
totalPages: chunks.length,
@@ -264,7 +273,9 @@ const postProcess = (allData, allSnippetData, parentLog) => {
fs.ensureDirSync(outDir);
await fs.writeFile(
`${outDir}/recommendations.json`,
- JSON.stringify(recommendedSnippets, null, 2)
+ JSON.stringify({
+ recommendedSnippets,
+ }, null, 2)
);
}
});
From af9ca507ee5e3900d79677e2047eae7a2297ca8e Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 21:55:14 +0300
Subject: [PATCH 13/39] Replace GraphQL layer with home-brewed system
Pass generated data to createPages, cut out sourceNodes,
querying, graphQL, transformations etc.
---
gatsby-node.js | 9 +-
src/build/createPages.js | 25 ++
src/build/createPages/createListingPages.js | 300 ------------------
src/build/createPages/createSnippetPages.js | 40 ---
src/build/createPages/createStaticPage.js | 12 -
.../createPages/createStaticPage.test.js | 18 --
src/build/createPages/index.js | 108 -------
src/build/index.js | 2 -
src/build/parsers/index.js | 2 -
src/build/parsers/parseQueries.js | 26 --
src/build/parsers/parseQueries.test.js | 40 ---
src/build/parsers/parseRequirables.js | 22 +-
src/build/parsers/parseRequirables.test.js | 13 +-
src/build/sourceNodes.js | 36 ---
src/build/sourceNodes.test.js | 40 ---
src/queries/createPagesQuery.graphql | 189 -----------
src/queries/getSearchIndex.graphql | 27 --
17 files changed, 54 insertions(+), 855 deletions(-)
create mode 100644 src/build/createPages.js
delete mode 100644 src/build/createPages/createListingPages.js
delete mode 100644 src/build/createPages/createSnippetPages.js
delete mode 100644 src/build/createPages/createStaticPage.js
delete mode 100644 src/build/createPages/createStaticPage.test.js
delete mode 100644 src/build/createPages/index.js
delete mode 100644 src/build/parsers/parseQueries.js
delete mode 100644 src/build/parsers/parseQueries.test.js
delete mode 100644 src/build/sourceNodes.js
delete mode 100644 src/build/sourceNodes.test.js
delete mode 100644 src/queries/createPagesQuery.graphql
delete mode 100644 src/queries/getSearchIndex.graphql
diff --git a/gatsby-node.js b/gatsby-node.js
index a267e81ce..73a2d7551 100644
--- a/gatsby-node.js
+++ b/gatsby-node.js
@@ -2,12 +2,10 @@ const { green } = require('chalk');
const env = require('./.build/env').default;
const {
- sourceNodes,
createPages,
onCreateWebpackConfig,
} = require(`./src/build`);
const {
- parseQueries,
parseRequirables,
parseTemplates,
} = require(`./src/build/parsers`);
@@ -19,11 +17,6 @@ console.log(`${green('success')} parse requirables`);
const templates = parseTemplates(env === 'DEVELOPMENT' ? paths.devTemplates : paths.templates, paths.templatesPath);
console.log(`${green('success')} parse templates`);
-const pagesQuery = parseQueries(paths.queryPath);
-console.log(`${green('success')} parse queries`);
-
-exports.createPages = createPages(pagesQuery, templates, requirables);
-
-exports.sourceNodes = sourceNodes(requirables);
+exports.createPages = createPages(templates, requirables);
exports.onCreateWebpackConfig = onCreateWebpackConfig;
diff --git a/src/build/createPages.js b/src/build/createPages.js
new file mode 100644
index 000000000..b0184a959
--- /dev/null
+++ b/src/build/createPages.js
@@ -0,0 +1,25 @@
+/**
+ * Tell plugins to add pages.
+ * Takes a list of requirable objects and a templates object.
+ * Creates pages by running createPage for each ne.
+ */
+const createPages = (templates, requirables) => ({ actions }) => {
+ const { createPage } = actions;
+
+ requirables.forEach(req =>
+ createPage({
+ path: req.relRoute,
+ component: templates[req.template],
+ context: req.context,
+ })
+ );
+
+ const mainListing = requirables.find(req => req.context.isMainListing);
+ createPage({
+ path: '/',
+ component: templates[mainListing.template],
+ context: mainListing.context,
+ });
+};
+
+export default createPages;
diff --git a/src/build/createPages/createListingPages.js b/src/build/createPages/createListingPages.js
deleted file mode 100644
index c32933692..000000000
--- a/src/build/createPages/createListingPages.js
+++ /dev/null
@@ -1,300 +0,0 @@
-import { chunk } from 'utils';
-import { transformSnippetIndex } from 'build/transformers';
-import EXPERTISE_LEVELS from 'config/expertise';
-import literals from 'lang/en/listing';
-
-const ORDERS_MAP = {
- 'p': literals.orders.popularity,
- 'a': literals.orders.alphabetical,
- 'e': literals.orders.expertise,
-};
-
-const CARDS_PER_PAGE = 40;
-
-/**
- * Creates listing pages from the data provided.
- * @param {*} indexedChunks - Chunked snippets.
- * @param {*} listingPage - Listing page template.
- * @param {*} createPage - Page creation method from gatsby.
- * @param {*} context - Page context.
- * @param {*} baseUrl - Base url slug.
- * @param {*} slugOrderingSegment - Ordering segment for the url slug.
- * @param {*} ordersList - List of orders.
- */
-const createListingPages = (
- indexedChunks,
- listingPage,
- createPage,
- context,
- baseUrl,
- slugOrderingSegment,
- ordersList
-) => {
- indexedChunks.forEach((chunk, i, chunks) => {
- createPage({
- path: `${baseUrl}/${slugOrderingSegment}/${i + 1}`,
- component: listingPage,
- context: {
- snippetList: chunk,
- paginator: {
- pageNumber: i + 1,
- totalPages: chunks.length,
- baseUrl,
- slugOrderingSegment,
- },
- sorter: {
- orders: ordersList.map(order => (
- {
- url: `${baseUrl}/${order}/1`,
- title: ORDERS_MAP[order],
- }
- )),
- selectedOrder: ORDERS_MAP[slugOrderingSegment],
- },
- ...context,
- },
- });
- });
- // Create Home page
- if (context.listingType === 'main' && slugOrderingSegment === 'p') {
- createPage({
- path: `/`,
- component: listingPage,
- context: {
- snippetList: indexedChunks[0],
- paginator: {
- pageNumber: 1,
- totalPages: indexedChunks.length,
- baseUrl,
- slugOrderingSegment,
- },
- sorter: {
- orders: ordersList.map(order => (
- {
- url: `${baseUrl}/${order}/1`,
- title: ORDERS_MAP[order],
- }
- )),
- selectedOrder: ORDERS_MAP[slugOrderingSegment],
- },
- ...context,
- },
- });
- }
-};
-
-/**
- * Creates listing pages using the provided orders and customization.
- * @param {*} listingPage - Listing page template.
- * @param {*} createPage - Page creation method from gatsby.
- * @param {*} context - Page context.
- * @param {*} baseUrl - Base url slug.
- * @param {*} orders - List of orders.
- * @param {*} chunks - Chunked snippets.
- * @param {*} contextCustomizer - A function for customizing context based on order.
- */
-const createListingPagesWithOrderOptions = (
- listingPage,
- createPage,
- context,
- baseUrl,
- orders,
- chunks,
- contextCustomizer = () => ({})
-) => {
- orders.forEach((order, i) => {
- createListingPages(
- chunks[i],
- listingPage,
- createPage,
- { ...context, ...contextCustomizer(order, i)},
- baseUrl,
- order,
- orders
- );
- });
-};
-
-/**
- * (Export) Creates all the listing pages, including data for order options.
- * @param {*} searchIndex - The raw search index data.
- * @param {*} listingMetas - Listing pages metadata.
- * @param {*} listingPage - Listing page template.
- * @param {*} createPage - Page creation method from gatsby.
- * @param {*} context - Page context.
- */
-/* eslint-disable no-extra-boolean-cast */
-const createAllListingPages = (
- searchIndex,
- listingMetas,
- listingPage,
- createPage,
- context
-) => {
- // 1. Create listing pages for the main listing:
- // Tranform and chunk data for popularity, alphabetical and expertise ordering
- const transformedIndex = transformSnippetIndex(searchIndex.edges);
- const popularChunks = chunk(transformedIndex, CARDS_PER_PAGE);
- const alphabeticalChunks = chunk(transformedIndex.sort((a, b) =>
- a.title.localeCompare(b.title)
- ), CARDS_PER_PAGE);
- const expertiseChunks = chunk(transformedIndex.sort((a, b) =>
- a.expertise === b.expertise ? a.title.localeCompare(b.title) :
- !a.expertise ? 1 : !b.expertise ? -1 :
- EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
- ), CARDS_PER_PAGE);
- // Create main listing sublinks and customization method for context
- const mainListingSublinks = listingMetas
- .map(v => v.featured > 0 ? v : {...v, featured: 500 })
- .sort((a, b) => a.featured === b.featured ? a.name - b.name : a.featured - b.featured);
- const mainContextCustomizer = order => {
- return {
- listingSublinks: mainListingSublinks
- .map(l => ({
- ...l,
- url: l.url.replace('/p/1', `/${order}/1`),
- })),
- };
- };
- // Create the listing pages with the order options provided
- createListingPagesWithOrderOptions(
- listingPage,
- createPage,
- {
- ...context,
- listingName: literals.snippetList,
- listingTitle: literals.snippetList,
- listingType: 'main',
- listingSublinks: mainListingSublinks,
- pageDescription: literals.pageDescription('main', {
- snippetCount: transformedIndex.length,
- }),
- },
- '/list',
- ['p', 'a', 'e'],
- [popularChunks, alphabeticalChunks, expertiseChunks],
- mainContextCustomizer
- );
-
- // 2. Create listing pages for the language listings
- listingMetas.forEach(listingMeta => {
- // Determine slug prefix and relevant information, create chunks from data for
- // each of the ordering options
- const slugPrefix = listingMeta.slugPrefix;
- const searchIndexName = searchIndex.edges
- .find(s => s.node.slug.startsWith(`${slugPrefix}`)).node.language.long || '';
- const searchIndexSlugData = searchIndex.edges.filter(s =>
- s.node.slug.startsWith(`${slugPrefix}`) ||
- (s.node.blog && s.node.tags.all.find(t => t.toLowerCase() === searchIndexName.toLowerCase()))
- );
- const transformedSlugChunks = transformSnippetIndex(searchIndexSlugData);
- const popularSlugChunks = chunk(transformedSlugChunks, CARDS_PER_PAGE);
- const alphabeticalSlugChunks = chunk(transformedSlugChunks.sort((a, b) =>
- a.title.localeCompare(b.title)
- ), CARDS_PER_PAGE);
- const expertiseSlugChunks = chunk(transformedSlugChunks.sort((a, b) =>
- a.expertise === b.expertise ? a.title.localeCompare(b.title) :
- !a.expertise ? 1 : !b.expertise ? -1 :
- EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
- ), CARDS_PER_PAGE);
- // Determine tag prefixes for the listing
- const searchIndexTagPrefixes = listingMeta.tags;
- const slugContextCustomizer = order => {
- return {
- listingSublinks: listingMeta.blog ? [] : [
- {
- url: `${slugPrefix}/${order}/1`,
- name: literals.tag('all'),
- selected: true,
- },
- ...listingMeta.tags
- .map(tag => ({
- url: `${slugPrefix}/t/${tag}/${order}/1`,
- name: literals.tag(tag),
- })),
- ],
- };
- };
- // Create the listing pages with the order options provided
- createListingPagesWithOrderOptions(
- listingPage,
- createPage,
- {
- ...context,
- listingName: listingMeta.blog ? literals.blog : literals.codelang(searchIndexName),
- listingTitle: listingMeta.blog ? literals.blog : literals.codelang(searchIndexName),
- listingType: listingMeta.blog ? 'blog' : 'language',
- pageDescription: literals.pageDescription(listingMeta.blog ? 'blog' : 'language', {
- snippetCount: searchIndexSlugData.length,
- listingLanguage: listingMeta.blog ? 'blog' : searchIndexName,
- }),
- },
- `${slugPrefix}`,
- ['p', 'a', 'e'],
- [popularSlugChunks, alphabeticalSlugChunks, expertiseSlugChunks],
- slugContextCustomizer
- );
-
- // 3. Create listing pages for the tag listings
- searchIndexTagPrefixes.forEach(tagPrefix => {
- // Determine slug prefix and relevant information, create chunks from data
- // for each of the ordering options
- const searchIndexTagData = searchIndex.edges
- .filter(s =>
- s.node.tags.primary === tagPrefix && s.node.slug.startsWith(`${slugPrefix}`) ||
- ( s.node.blog &&
- s.node.tags.all.find(t => t.toLowerCase() === searchIndexName.toLowerCase()) &&
- s.node.tags.all.find(t => t.toLowerCase() === tagPrefix.toLowerCase())
- )
- );
- const transformedTagChunks = transformSnippetIndex(searchIndexTagData);
- const popularTagChunks = chunk(transformedTagChunks, CARDS_PER_PAGE);
- const alphabeticalTagChunks = chunk(transformedTagChunks.sort((a, b) =>
- a.title.localeCompare(b.title)
- ), CARDS_PER_PAGE);
- const expertiseTagChunks = chunk(transformedTagChunks.sort((a, b) =>
- a.expertise === b.expertise ? a.title.localeCompare(b.title) :
- !a.expertise ? 1 : !b.expertise ? -1 :
- EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
- ), CARDS_PER_PAGE);
- const tagContextCustomizer = order => {
- return {
- listingSublinks: listingMeta.blog ? [] : [
- {
- url: `${slugPrefix}/${order}/1`,
- name: literals.tag('all'),
- selected: true,
- },
- ...listingMeta.tags
- .map(tag => ({
- url: `${slugPrefix}/t/${tag}/${order}/1`,
- name: literals.tag(tag),
- })),
- ].map(tag => ({ ...tag, selected: tag.url.indexOf(`/t/${tagPrefix}/`) !== -1 })),
- };
- };
- // Create the listing pages with the order options provided
- createListingPagesWithOrderOptions(
- listingPage,
- createPage,
- {
- ...context,
- listingName: literals.codelangTag(searchIndexName, tagPrefix),
- listingTitle: literals.codelang(searchIndexName),
- listingType: 'tag',
- pageDescription: literals.pageDescription('tag', {
- snippetCount: searchIndexSlugData.length,
- listingLanguage: searchIndexName,
- listingTag: tagPrefix,
- }),
- },
- `${slugPrefix}/t/${tagPrefix}`,
- ['p', 'a', 'e'],
- [popularTagChunks, alphabeticalTagChunks, expertiseTagChunks],
- tagContextCustomizer
- );
- });
- });
-};
-
-export default createAllListingPages;
diff --git a/src/build/createPages/createSnippetPages.js b/src/build/createPages/createSnippetPages.js
deleted file mode 100644
index 4e0ced8f3..000000000
--- a/src/build/createPages/createSnippetPages.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import {
- transformSnippetIndex,
- transformSnippetContext,
- transformSnippetDescription,
- transformBreadcrumbs
-} from 'build/transformers';
-
-/**
- * Creates individual snippet pages.
- * @param {array} snippets - An array of snippets.
- * @param {*} snippetPage - Snippet page template.
- * @param {*} createPage - Page creation method from gatsby.
- * @param {*} commonContext - Context to be passed to the page.
- * @param {array} imageContext - Image context.
- */
-const createSnippetPages = (
- snippets,
- snippetPage,
- createPage,
- commonContext
-) => {
- snippets.forEach(snippet => {
- const recommendedSnippets = transformSnippetIndex(
- snippet.node.recommendedSnippets.map(v => ( { node: v }))
- );
- createPage({
- path: `${snippet.node.slug}`,
- component: snippetPage,
- context: {
- snippet: transformSnippetContext(snippet.node, commonContext.cardTemplate),
- ...commonContext,
- recommendedSnippets,
- breadcrumbs: transformBreadcrumbs(snippet.node, commonContext.cardTemplate),
- pageDescription: transformSnippetDescription(snippet.node, commonContext.cardTemplate),
- },
- });
- });
-};
-
-export default createSnippetPages;
diff --git a/src/build/createPages/createStaticPage.js b/src/build/createPages/createStaticPage.js
deleted file mode 100644
index fbb04e9a7..000000000
--- a/src/build/createPages/createStaticPage.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * Responsible for creating static pages (about, cookies, search, settings etc).
- * @param {*} component - Static page template to be used.
- * @param {*} createPage - Page creation method from gatsby.
- * @param {*} context - Context to be passed to the page.
- * @param {*} path - Page URL.
- */
-const createStaticPage = (component, createPage, context, path) => {
- createPage({ path, component, context });
-};
-
-export default createStaticPage;
diff --git a/src/build/createPages/createStaticPage.test.js b/src/build/createPages/createStaticPage.test.js
deleted file mode 100644
index fcd0ae8b2..000000000
--- a/src/build/createPages/createStaticPage.test.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import createStaticPage from './createStaticPage';
-
-const createPageMock = jest.fn();
-
-describe('createStaticPage', () => {
- beforeAll(() => {
- createStaticPage('my-component', createPageMock, 'test', '/static');
- });
-
- it('calls createPage with the correct arguments', () => {
- expect(createPageMock.mock.calls.length).toBe(1);
- expect(createPageMock).toHaveBeenCalledWith({
- path: '/static',
- component: 'my-component',
- context: 'test',
- });
- });
-});
diff --git a/src/build/createPages/index.js b/src/build/createPages/index.js
deleted file mode 100644
index df7f02991..000000000
--- a/src/build/createPages/index.js
+++ /dev/null
@@ -1,108 +0,0 @@
-import createStaticPage from './createStaticPage';
-import createListingPages from './createListingPages';
-import createSnippetPages from './createSnippetPages';
-import { transformSnippetIndex } from 'build/transformers';
-import literals from 'lang/en';
-
-/**
- * Tell plugins to add pages.
- * Takes a query string and a templates object.
- * Takes a list of requirable objects after being loaded.
- * Creates pages by running individual methods.
- */
-const createPages = (query, templates, requirables) => ({ graphql, actions }) => {
- const { createPage } = actions;
-
- return graphql(query)
- .then(result => {
- if (result.errors) throw result.errors;
-
- const searchIndex = result.data.searchIndex;
- const listingMetas = requirables.map(rq => rq.meta);
-
- createStaticPage(
- templates['NotFoundPage'],
- createPage,
- {},
- '/404'
- );
-
- createStaticPage(
- templates['StaticPage'],
- createPage,
- {
- stringLiterals: literals.about,
- },
- '/about'
- );
-
- createStaticPage(
- templates['StaticPage'],
- createPage,
- {
- stringLiterals: literals.cookies,
- },
- '/cookies'
- );
-
- createStaticPage(
- templates['SettingsPage'],
- createPage,
- {
- stringLiterals: literals.settings,
- },
- '/settings'
- );
-
- createListingPages(
- searchIndex,
- listingMetas,
- templates['ListingPage'],
- createPage,
- {},
- '/list'
- );
-
- createSnippetPages(
- result.data.simpleSnippets.edges,
- templates['SnippetPage'],
- createPage,
- {
- cardTemplate: 'StandardSnippetCard',
- }
- );
-
- createSnippetPages(
- result.data.cssSnippets.edges,
- templates['SnippetPage'],
- createPage,
- {
- cardTemplate: 'CssSnippetCard',
- }
- );
-
- createSnippetPages(
- result.data.blogSnippets.edges,
- templates['SnippetPage'],
- createPage,
- {
- cardTemplate: 'BlogSnippetCard',
- }
- );
-
- createStaticPage(
- templates['SearchPage'],
- createPage,
- {
- searchIndex: transformSnippetIndex(searchIndex.edges, true),
- recommendedSnippets: transformSnippetIndex(searchIndex.edges.slice(0, 3)),
- pageDescription: literals.search.pageDescription(searchIndex.edges.length),
- },
- '/search'
- );
-
- return null;
- });
-};
-
-export default createPages;
diff --git a/src/build/index.js b/src/build/index.js
index 959d0d2be..7af14bea1 100644
--- a/src/build/index.js
+++ b/src/build/index.js
@@ -1,9 +1,7 @@
-import sourceNodes from './sourceNodes';
import createPages from './createPages';
import onCreateWebpackConfig from './onCreateWebpackConfig';
export {
- sourceNodes,
createPages,
onCreateWebpackConfig,
};
diff --git a/src/build/parsers/index.js b/src/build/parsers/index.js
index 5a8e62ca4..d981e4928 100644
--- a/src/build/parsers/index.js
+++ b/src/build/parsers/index.js
@@ -1,9 +1,7 @@
-import parseQueries from './parseQueries';
import parseRequirables from './parseRequirables';
import parseTemplates from './parseTemplates';
export {
- parseQueries,
parseRequirables,
parseTemplates
};
diff --git a/src/build/parsers/parseQueries.js b/src/build/parsers/parseQueries.js
deleted file mode 100644
index 127474fda..000000000
--- a/src/build/parsers/parseQueries.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import glob from 'glob';
-import fs from 'fs-extra';
-import path from 'path';
-
-/**
- * Combines the given GraphQL queries in the given directory, returning a
- * single query string to be run against the GraphQL schema.
- * @param {string} contentDirPath - The path to the queries directory.
- */
-const parseQueries = queryDirPath => {
- // Load queries
- let queries = [];
- glob.sync(`${queryDirPath}/*.graphql`)
- .forEach( file => {
- queries.push(
- fs.readFileSync(path.resolve(`${file}`), 'utf8')
- .replace(/^query\s+{\n/g, '\n')
- .replace(/\n}\n*$/g, '\n')
- );
- });
- return `query {
- ${queries.join('\n')}
- }`;
-};
-
-export default parseQueries;
diff --git a/src/build/parsers/parseQueries.test.js b/src/build/parsers/parseQueries.test.js
deleted file mode 100644
index acb0fffa6..000000000
--- a/src/build/parsers/parseQueries.test.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import parseQueries from './parseQueries';
-
-import glob from 'glob';
-import fs from 'fs-extra';
-import path from 'path';
-
-jest.mock('glob');
-jest.mock('path');
-jest.mock('fs-extra');
-
-const mockQuery = `query {
- searchIndex: allSnippet(
- sort: {fields: ranking, order: DESC}
- ) {
- edges {
- node {
- slug
- }
- }
- }
-}`;
-
-glob.sync.mockImplementation(jest.fn(() => ['my-query.graphql']));
-path.resolve.mockImplementation(jest.fn(f => f));
-fs.readFileSync.mockImplementation(() => mockQuery);
-
-let resultQuery;
-
-describe('parseQueries', () => {
- beforeAll(() => {
- resultQuery = parseQueries('my-queries-dir');
- });
- it('returns a usable GraphQL query', () => {
- expect(resultQuery.indexOf('query')).not.toBe(-1);
- expect(resultQuery.indexOf('searchIndex')).not.toBe(-1);
- expect(resultQuery.indexOf('edges')).not.toBe(-1);
- expect(resultQuery.indexOf('node')).not.toBe(-1);
- expect(resultQuery.indexOf('slug')).not.toBe(-1);
- });
-});
diff --git a/src/build/parsers/parseRequirables.js b/src/build/parsers/parseRequirables.js
index 0326e34a3..2b7e079c1 100644
--- a/src/build/parsers/parseRequirables.js
+++ b/src/build/parsers/parseRequirables.js
@@ -9,11 +9,25 @@ import path from 'path';
const parseRequirables = contentDirPath => {
// Load configurations
let requirables = [];
- glob.sync(`${contentDirPath}/*.json`)
+ glob
+ .sync(`${contentDirPath}/**/index.json`)
.forEach( file => {
- requirables.push(
- require( path.resolve( file ) )
- );
+ const dir = file.slice(0, file.lastIndexOf('/'));
+ const reqData = glob
+ .sync(`${dir}/!(index).json`)
+ .reduce((acc, dataFile) => {
+ const data = require(path.resolve(dataFile));
+ acc.context = {
+ ...acc.context,
+ ...data,
+ };
+ return acc;
+ },
+ {
+ ...require(path.resolve(file)),
+ context: {},
+ });
+ requirables.push(reqData);
});
return requirables;
};
diff --git a/src/build/parsers/parseRequirables.test.js b/src/build/parsers/parseRequirables.test.js
index 03a43e05d..d5464fd42 100644
--- a/src/build/parsers/parseRequirables.test.js
+++ b/src/build/parsers/parseRequirables.test.js
@@ -44,7 +44,13 @@ const mockRequirables = {
},
};
-glob.sync.mockImplementation(jest.fn(() => ['stdRequirable.json', 'ltdRequirable.json']));
+glob.sync.mockImplementation(
+ jest
+ .fn()
+ .mockReturnValueOnce(['stdRequirable.json', 'ltdRequirable.json'])
+ .mockReturnValueOnce(['stdRequirable.json'])
+ .mockReturnValueOnce(['ltdRequirable.json'])
+);
path.resolve.mockImplementation(jest.fn(f => f));
// eslint-disable-next-line no-unused-vars
@@ -60,9 +66,10 @@ jest.mock('ltdRequirable.json',
describe('parseRequirables', () => {
it('returns the array of the resulting requirables', () => {
+ console.log();
expect(parseRequirables('my-content-dir')).toEqual([
- mockRequirables['stdRequirable'],
- mockRequirables['ltdRequirable'],
+ {...mockRequirables['stdRequirable'], context: mockRequirables['stdRequirable'] },
+ {...mockRequirables['ltdRequirable'], context: mockRequirables['ltdRequirable']},
]);
});
});
diff --git a/src/build/sourceNodes.js b/src/build/sourceNodes.js
deleted file mode 100644
index bb247799e..000000000
--- a/src/build/sourceNodes.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import schema from 'typedefs';
-
-/**
- * Extension point to tell plugins to source nodes.
- * Defines the custom Snippet type.
- * Populates the newly-created nodes.
- * API docs: https://www.gatsbyjs.org/docs/node-apis/#sourceNodes
- */
-const sourceNodes = requirables => ({ actions, createNodeId, createContentDigest }) => {
- const { createTypes, createNode } = actions;
-
- // Create the GraphQL schema, adding the custom types
- const typeDefs = `${schema}`;
- createTypes(typeDefs);
-
- // Use the passed requirables (JSON files) to create the GraphQL nodes for
- // the snippet data nodes they include.
- requirables
- .forEach(sArr => {
- sArr.data.forEach(sNode => {
- createNode({
- id: createNodeId(`snippet${sNode.slug}`),
- parent: null,
- children: [],
- internal: {
- type: 'Snippet',
- content: JSON.stringify(sNode),
- contentDigest: createContentDigest(sNode),
- },
- ...sNode,
- });
- });
- });
-};
-
-export default sourceNodes;
diff --git a/src/build/sourceNodes.test.js b/src/build/sourceNodes.test.js
deleted file mode 100644
index ce1a3ebbf..000000000
--- a/src/build/sourceNodes.test.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import sourceNodes from './sourceNodes';
-import { requirables } from 'fixtures/requirables';
-
-const createTypesMock = jest.fn();
-const createNodeMock = jest.fn();
-const actions = {
- createTypes: createTypesMock,
- createNode: createNodeMock,
-};
-
-const createNodeIdMock = jest.fn(s => s);
-const createContentDigestMock = jest.fn(() => null);
-const getNodesByTypeMock = jest.fn().mockReturnValue([
- {fileAbsolutePath: '30code/snippets/all.md'},
- {fileAbsolutePath: '30code/snippets/allEqual.md'},
- {fileAbsolutePath: '30csharp/snippets/FindIndexOfLastBy.md'},
- {fileAbsolutePath: '30csharp/snippets/FindLastBy.md'},
-]);
-
-describe('sourceNodes', () => {
- beforeAll(() => {
- sourceNodes(requirables)({
- actions,
- createNodeId: createNodeIdMock,
- createContentDigest: createContentDigestMock,
- getNodesByType: getNodesByTypeMock,
- });
- });
-
- it('calls createTypes once', () => {
- expect(createTypesMock.mock.calls.length).toBe(1);
- });
-
- it('calls createNode, createNodeId and createContentDigest once for each snippet', () => {
- expect(createNodeMock.mock.calls.length).toBe(4);
- expect(createNodeIdMock.mock.calls.length).toBe(4);
- expect(createContentDigestMock.mock.calls.length).toBe(4);
- });
-});
-
diff --git a/src/queries/createPagesQuery.graphql b/src/queries/createPagesQuery.graphql
deleted file mode 100644
index 87425b9f9..000000000
--- a/src/queries/createPagesQuery.graphql
+++ /dev/null
@@ -1,189 +0,0 @@
-query {
- simpleSnippets: allSnippet(
- sort: {fields: id},
- filter: {code: {src: {ne: null}}}
- ) {
- edges {
- node {
- id
- slug
- url
- tags {
- all
- primary
- }
- text {
- full
- short
- }
- title
- html {
- code
- example
- style
- description
- fullDescription
- }
- code {
- src
- example
- style
- }
- expertise
- ranking
- firstSeen
- lastUpdated
- language {
- long
- short
- otherLanguages {
- short
- long
- }
- }
- icon
- searchTokens
- recommendedSnippets {
- id
- title
- expertise
- icon
- slug
- tags {
- primary
- }
- expertise
- language {
- short
- long
- }
- searchTokens
- html {
- description
- }
- }
- }
- }
- }
-
- cssSnippets: allSnippet(
- sort: {fields: id},
- filter: {language: {short: {eq: "css"}}}
- ) {
- edges {
- node {
- id
- slug
- url
- tags {
- all
- primary
- }
- text {
- full
- short
- }
- title
- html {
- html
- css
- js
- description
- fullDescription
- }
- code {
- html
- css
- js
- scopedCss
- }
- expertise
- ranking
- firstSeen
- lastUpdated
- language {
- long
- short
- }
- icon
- searchTokens
- recommendedSnippets {
- id
- title
- expertise
- icon
- slug
- tags {
- primary
- }
- expertise
- language {
- short
- long
- }
- searchTokens
- html {
- description
- }
- }
- }
- }
- }
-
- blogSnippets: allSnippet(
- sort: {fields: firstSeen, order: DESC},
- filter: {blog: {eq: true}}
- ) {
- edges {
- node {
- id
- slug
- url
- tags {
- all
- primary
- }
- text {
- full
- short
- }
- title
- html {
- description
- fullDescription
- }
- expertise
- ranking
- firstSeen
- lastUpdated
- authors {
- name
- profile
- }
- icon
- cover
- blog
- searchTokens
- recommendedSnippets {
- id
- title
- expertise
- icon
- slug
- tags {
- primary
- }
- expertise
- language {
- short
- long
- }
- searchTokens
- html {
- description
- }
- }
- }
- }
- }
-}
diff --git a/src/queries/getSearchIndex.graphql b/src/queries/getSearchIndex.graphql
deleted file mode 100644
index b729d71d3..000000000
--- a/src/queries/getSearchIndex.graphql
+++ /dev/null
@@ -1,27 +0,0 @@
-query {
- searchIndex: allSnippet(
- sort: {fields: ranking, order: DESC}
- ) {
- edges {
- node {
- slug
- blog
- title
- html {
- description
- }
- tags {
- primary
- all
- }
- expertise
- language {
- short
- long
- }
- icon
- searchTokens
- }
- }
- }
-}
From 0dddde904fbfa73316873a4034420cc0d96f22df Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 21:58:17 +0300
Subject: [PATCH 14/39] Move gatsby lifecycle hooks to own directory
---
gatsby-node.js | 2 +-
src/{build => gatsby}/createPages.js | 0
src/{build => gatsby}/index.js | 0
src/{build => gatsby}/onCreateWebpackConfig.js | 0
src/{build => gatsby}/onCreateWebpackConfig.test.js | 0
5 files changed, 1 insertion(+), 1 deletion(-)
rename src/{build => gatsby}/createPages.js (100%)
rename src/{build => gatsby}/index.js (100%)
rename src/{build => gatsby}/onCreateWebpackConfig.js (100%)
rename src/{build => gatsby}/onCreateWebpackConfig.test.js (100%)
diff --git a/gatsby-node.js b/gatsby-node.js
index 73a2d7551..0bd31ffec 100644
--- a/gatsby-node.js
+++ b/gatsby-node.js
@@ -4,7 +4,7 @@ const env = require('./.build/env').default;
const {
createPages,
onCreateWebpackConfig,
-} = require(`./src/build`);
+} = require(`./src/gatsby`);
const {
parseRequirables,
parseTemplates,
diff --git a/src/build/createPages.js b/src/gatsby/createPages.js
similarity index 100%
rename from src/build/createPages.js
rename to src/gatsby/createPages.js
diff --git a/src/build/index.js b/src/gatsby/index.js
similarity index 100%
rename from src/build/index.js
rename to src/gatsby/index.js
diff --git a/src/build/onCreateWebpackConfig.js b/src/gatsby/onCreateWebpackConfig.js
similarity index 100%
rename from src/build/onCreateWebpackConfig.js
rename to src/gatsby/onCreateWebpackConfig.js
diff --git a/src/build/onCreateWebpackConfig.test.js b/src/gatsby/onCreateWebpackConfig.test.js
similarity index 100%
rename from src/build/onCreateWebpackConfig.test.js
rename to src/gatsby/onCreateWebpackConfig.test.js
From 15f80cd22ad9cedae3b3e8e3cc99a9c2ae952c68 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 22:17:53 +0300
Subject: [PATCH 15/39] Update transformSnippets for new data layer
Remove GraphQL artifacts
---
src/build/transformers/transformSnippets.js | 22 ++--
.../transformers/transformSnippets.test.js | 100 ++++++++----------
src/yild/extractSnippets/postProcess.js | 14 +--
src/yild/serveSnippets/index.js | 2 +-
4 files changed, 63 insertions(+), 75 deletions(-)
diff --git a/src/build/transformers/transformSnippets.js b/src/build/transformers/transformSnippets.js
index 63afb9c53..3888277ee 100644
--- a/src/build/transformers/transformSnippets.js
+++ b/src/build/transformers/transformSnippets.js
@@ -5,19 +5,19 @@ import literals from 'lang/en/snippet';
/**
* Transform the indexed snippets to the appropriate format.
* Used in listing pages to render snippet previews.
- * @param {array} edges - An array of snippet edges.
+ * @param {array} snippets - An array of snippets.
* @param {bool} withSearchTokens - Should include search tokens in the result?
*/
-export const transformSnippetIndex = (edges, withSearchTokens = false) =>
- edges.map(({ node }) => ({
- title: node.title,
- expertise: transformTagName(node.expertise),
- primaryTag: transformTagName(node.tags.primary),
- language: node.language && node.language.long ? node.language.long : undefined,
- icon: node.icon,
- description: node.html.description.trim(),
- url: node.slug,
- ...(withSearchTokens ? { searchTokens: node.searchTokens } : {}),
+export const transformSnippetIndex = (snippets, withSearchTokens = false) =>
+ snippets.map(snippet => ({
+ title: snippet.title,
+ expertise: transformTagName(snippet.expertise),
+ primaryTag: transformTagName(snippet.tags.primary),
+ language: snippet.language && snippet.language.long ? snippet.language.long : undefined,
+ icon: snippet.icon,
+ description: snippet.html.description.trim(),
+ url: snippet.slug,
+ ...(withSearchTokens ? { searchTokens: snippet.searchTokens } : {}),
}));
/**
diff --git a/src/build/transformers/transformSnippets.test.js b/src/build/transformers/transformSnippets.test.js
index d950120b4..ef4c9404a 100644
--- a/src/build/transformers/transformSnippets.test.js
+++ b/src/build/transformers/transformSnippets.test.js
@@ -6,82 +6,76 @@ import {
describe('transformSnippetIndex', () => {
it('transforms the snippet index', () => {
- const edges = [
+ const snippets = [
{
- node: {
- title: 'a',
- expertise: 'Intermediate',
- tags: {
- primary: 'array',
- },
- language: {
- long: 'lang',
- short: 'l',
- },
- html: {
- description: 'desc ',
- },
- slug: '/a',
- searchTokens: '',
- irrelevantStuff: 'data',
+ title: 'a',
+ expertise: 'Intermediate',
+ tags: {
+ primary: 'array',
},
+ language: {
+ long: 'lang',
+ short: 'l',
+ },
+ html: {
+ description: 'desc ',
+ },
+ slug: '/a',
+ searchTokens: '',
+ irrelevantStuff: 'data',
},
];
- const result = transformSnippetIndex(edges);
- expect(result[0].title).toBe(edges[0].node.title);
+ const result = transformSnippetIndex(snippets);
+ expect(result[0].title).toBe(snippets[0].title);
expect(result[0].expertise).toBe('Intermediate');
expect(result[0].primaryTag).toBe('Array');
- expect(result[0].language).toBe(edges[0].node.language.long);
- expect(result[0].description).toBe(edges[0].node.html.description.trim());
- expect(result[0].url).toBe(edges[0].node.slug);
+ expect(result[0].language).toBe(snippets[0].language.long);
+ expect(result[0].description).toBe(snippets[0].html.description.trim());
+ expect(result[0].url).toBe(snippets[0].slug);
expect(result[0].searchTokens).toBe(undefined);
expect(result[0].irrelevantStuff).toBe(undefined);
});
it('handles an empty language appropriately', () => {
- const edges = [
+ const snippets = [
{
- node: {
- title: 'a',
- expertise: 'Intermediate',
- tags: {
- primary: 'array',
- },
- language: {},
- html: {
- description: 'desc ',
- },
- slug: '/a',
- searchTokens: '',
- irrelevantStuff: 'data',
+ title: 'a',
+ expertise: 'Intermediate',
+ tags: {
+ primary: 'array',
},
+ language: {},
+ html: {
+ description: 'desc ',
+ },
+ slug: '/a',
+ searchTokens: '',
+ irrelevantStuff: 'data',
},
];
- const result = transformSnippetIndex(edges);
+ const result = transformSnippetIndex(snippets);
expect(result[0].language).toBe(undefined);
});
it('returns search tokens when explicitly told to do so', () => {
- const edges = [
+ const snippets = [
{
- node: {
- title: 'a',
- expertise: 'Intermediate',
- tags: {
- primary: 'array',
- },
- language: {},
- html: {
- description: 'desc ',
- },
- slug: '/a',
- searchTokens: 'my tokens',
- irrelevantStuff: 'data',
+ title: 'a',
+ expertise: 'Intermediate',
+ tags: {
+ primary: 'array',
+ },
+ language: {},
+ html: {
+ description: 'desc ',
},
+ slug: '/a',
+ searchTokens: 'my tokens',
+ irrelevantStuff: 'data',
},
];
- const result = transformSnippetIndex(edges, true);
- expect(result[0].searchTokens).toBe(edges[0].node.searchTokens);
+ const result = transformSnippetIndex(snippets, true);
+ expect(result[0].searchTokens).toBe(snippets[0].searchTokens);
});
});
diff --git a/src/yild/extractSnippets/postProcess.js b/src/yild/extractSnippets/postProcess.js
index 8c9a616ce..59454becf 100644
--- a/src/yild/extractSnippets/postProcess.js
+++ b/src/yild/extractSnippets/postProcess.js
@@ -90,9 +90,7 @@ const compileListingPagesWithOrderOptions = (
const compileListingData = (snippetIndex, listingMetas) => {
// 1. Create listing pages for the main listing:
// Tranform and chunk data for popularity, alphabetical and expertise ordering
- const transformedIndex = transformSnippetIndex(
- snippetIndex.map(v => ( { node: v }))
- );
+ const transformedIndex = transformSnippetIndex(snippetIndex);
const popularChunks = chunk(transformedIndex, CARDS_PER_PAGE);
const alphabeticalChunks = chunk(transformedIndex.sort((a, b) =>
a.title.localeCompare(b.title)
@@ -143,9 +141,7 @@ const compileListingData = (snippetIndex, listingMetas) => {
s.slug.startsWith(`${slugPrefix}`) ||
(s.blog && s.tags.all.find(t => t.toLowerCase() === snippetIndexName.toLowerCase()))
);
- const transformedSlugChunks = transformSnippetIndex(
- snippetIndexSlugData.map(v => ( { node: v }))
- );
+ const transformedSlugChunks = transformSnippetIndex(snippetIndexSlugData);
const popularSlugChunks = chunk(transformedSlugChunks, CARDS_PER_PAGE);
const alphabeticalSlugChunks = chunk(transformedSlugChunks.sort((a, b) =>
a.title.localeCompare(b.title)
@@ -202,9 +198,7 @@ const compileListingData = (snippetIndex, listingMetas) => {
s.tags.all.find(t => t.toLowerCase() === tagPrefix.toLowerCase())
)
);
- const transformedTagChunks = transformSnippetIndex(
- snippetIndexTagData.map(v => ( { node: v }))
- );
+ const transformedTagChunks = transformSnippetIndex(snippetIndexTagData);
const popularTagChunks = chunk(transformedTagChunks, CARDS_PER_PAGE);
const alphabeticalTagChunks = chunk(transformedTagChunks.sort((a, b) =>
a.title.localeCompare(b.title)
@@ -266,7 +260,7 @@ const postProcess = (allData, allSnippetData, parentLog) => {
for (let snippet of data.data) {
const recommendedSnippets = transformSnippetIndex(
- recommendationEngine(allSnippetData, snippet).map(v => ( { node: v }))
+ recommendationEngine(allSnippetData, snippet)
);
const outDir = `${contentOutDir}/${snippet.slug.slice(1)}`;
diff --git a/src/yild/serveSnippets/index.js b/src/yild/serveSnippets/index.js
index 3d0030c1f..fb10cbb6f 100644
--- a/src/yild/serveSnippets/index.js
+++ b/src/yild/serveSnippets/index.js
@@ -72,7 +72,7 @@ const serveSnippets = () => {
case 1:
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(
- JSON.stringify(transformSnippetIndex(data.map(s => ({ node: s }))))
+ JSON.stringify(transformSnippetIndex(data))
);
break;
case 3: {
From 0fdceebe95ecf752ec0641fab1a322356a2198c1 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 22:49:22 +0300
Subject: [PATCH 16/39] Move parsers into gatsby directory
Combine remaining parsers into a single one,
move into gatsby directory for ease of importing.
---
content/sources/30blog | 2 +-
gatsby-node.js | 16 ++++----
src/build/parsers/index.js | 7 ----
src/build/parsers/parseRequirables.js | 35 ----------------
src/build/parsers/parseTemplates.js | 14 -------
src/build/parsers/parseTemplates.test.js | 26 ------------
src/gatsby/index.js | 2 +
src/gatsby/parseRequirements.js | 41 +++++++++++++++++++
.../parseRequirements.test.js} | 24 ++++++++++-
9 files changed, 73 insertions(+), 94 deletions(-)
delete mode 100644 src/build/parsers/index.js
delete mode 100644 src/build/parsers/parseRequirables.js
delete mode 100644 src/build/parsers/parseTemplates.js
delete mode 100644 src/build/parsers/parseTemplates.test.js
create mode 100644 src/gatsby/parseRequirements.js
rename src/{build/parsers/parseRequirables.test.js => gatsby/parseRequirements.test.js} (77%)
diff --git a/content/sources/30blog b/content/sources/30blog
index a14b59e4e..adbf1fbb9 160000
--- a/content/sources/30blog
+++ b/content/sources/30blog
@@ -1 +1 @@
-Subproject commit a14b59e4e041538da4526d2501f5949ed22318a7
+Subproject commit adbf1fbb9892bb776c37d700525e9e4d47fae52e
diff --git a/gatsby-node.js b/gatsby-node.js
index 0bd31ffec..97a72760e 100644
--- a/gatsby-node.js
+++ b/gatsby-node.js
@@ -4,18 +4,16 @@ const env = require('./.build/env').default;
const {
createPages,
onCreateWebpackConfig,
+ parseRequirements,
} = require(`./src/gatsby`);
-const {
- parseRequirables,
- parseTemplates,
-} = require(`./src/build/parsers`);
const paths = require(`./src/config/paths`);
-const requirables = parseRequirables(paths.contentPath);
-console.log(`${green('success')} parse requirables`);
-
-const templates = parseTemplates(env === 'DEVELOPMENT' ? paths.devTemplates : paths.templates, paths.templatesPath);
-console.log(`${green('success')} parse templates`);
+const { requirables, templates} = parseRequirements(
+ env === 'DEVELOPMENT' ? paths.devTemplates : paths.templates,
+ paths.templatesPath,
+ paths.contentPath
+);
+console.log(`${green('success')} parse requirements`);
exports.createPages = createPages(templates, requirables);
diff --git a/src/build/parsers/index.js b/src/build/parsers/index.js
deleted file mode 100644
index d981e4928..000000000
--- a/src/build/parsers/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import parseRequirables from './parseRequirables';
-import parseTemplates from './parseTemplates';
-
-export {
- parseRequirables,
- parseTemplates
-};
diff --git a/src/build/parsers/parseRequirables.js b/src/build/parsers/parseRequirables.js
deleted file mode 100644
index 2b7e079c1..000000000
--- a/src/build/parsers/parseRequirables.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import glob from 'glob';
-import path from 'path';
-
-/**
- * Combines the given data JSONs, using the data files
- * of the content, returning an array of objects from the files.
- * @param {string} contentDirPath - The path to the content directory.
- */
-const parseRequirables = contentDirPath => {
- // Load configurations
- let requirables = [];
- glob
- .sync(`${contentDirPath}/**/index.json`)
- .forEach( file => {
- const dir = file.slice(0, file.lastIndexOf('/'));
- const reqData = glob
- .sync(`${dir}/!(index).json`)
- .reduce((acc, dataFile) => {
- const data = require(path.resolve(dataFile));
- acc.context = {
- ...acc.context,
- ...data,
- };
- return acc;
- },
- {
- ...require(path.resolve(file)),
- context: {},
- });
- requirables.push(reqData);
- });
- return requirables;
-};
-
-export default parseRequirables;
diff --git a/src/build/parsers/parseTemplates.js b/src/build/parsers/parseTemplates.js
deleted file mode 100644
index 0666feb0e..000000000
--- a/src/build/parsers/parseTemplates.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const path = require(`path`);
-
-/**
- * Combines the given list of templates into an object.
- * @param {array} templates - An array of templates.
- * @param {string} templatesDir - The path to the template directory.
- */
-const parseTemplates = (templates, templatesDir) =>
- templates.reduce((acc, tmpl) => {
- acc[tmpl.name] = path.resolve(`${templatesDir}/${tmpl.path}`);
- return acc;
- }, {});
-
-export default parseTemplates;
diff --git a/src/build/parsers/parseTemplates.test.js b/src/build/parsers/parseTemplates.test.js
deleted file mode 100644
index b3a7475f6..000000000
--- a/src/build/parsers/parseTemplates.test.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import parseTemplates from './parseTemplates';
-
-import path from 'path';
-jest.mock('path');
-
-path.resolve.mockImplementation(jest.fn(f => f));
-
-const templates = [
- {
- 'name': 'SnippetPage',
- 'path': 'snippetPage/index.jsx',
- },
- {
- 'name': 'SearchPage',
- 'path': 'searchPage/index.jsx',
- },
-];
-
-describe('parseTemplates', () => {
- it('returns an object with the appropriate structure and data', () => {
- expect(parseTemplates(templates, 'my-templates-dir')).toEqual({
- 'SnippetPage': 'my-templates-dir/snippetPage/index.jsx',
- 'SearchPage': 'my-templates-dir/searchPage/index.jsx',
- });
- });
-});
diff --git a/src/gatsby/index.js b/src/gatsby/index.js
index 7af14bea1..b69f5b2c8 100644
--- a/src/gatsby/index.js
+++ b/src/gatsby/index.js
@@ -1,7 +1,9 @@
+import parseRequirements from './parseRequirements';
import createPages from './createPages';
import onCreateWebpackConfig from './onCreateWebpackConfig';
export {
+ parseRequirements,
createPages,
onCreateWebpackConfig,
};
diff --git a/src/gatsby/parseRequirements.js b/src/gatsby/parseRequirements.js
new file mode 100644
index 000000000..bd8cf6e01
--- /dev/null
+++ b/src/gatsby/parseRequirements.js
@@ -0,0 +1,41 @@
+import glob from 'glob';
+import path from 'path';
+
+/**
+ * Combines the given data JSONs, using the data files
+ * of the content, returning an array of objects from the files.
+ * @param {string} contentDir - The path to the content directory.
+ */
+export const parseRequirables = contentDir =>
+ glob.sync(`${contentDir}/**/index.json`).map(file =>
+ glob.sync(`${file.slice(0, file.lastIndexOf('/'))}/!(index).json`)
+ .reduce((acc, dataFile) => {
+ acc.context = { ...acc.context, ...require(path.resolve(dataFile)) };
+ return acc;
+ }, { ...require(path.resolve(file)), context: {} }));
+
+/**
+ * Combines the given list of templates into an object.
+ * @param {array} templates - An array of templates.
+ * @param {string} templatesDir - The path to the template directory.
+ */
+export const parseTemplates = (templates, templatesDir) =>
+ templates.reduce((acc, tmpl) => {
+ acc[tmpl.name] = path.resolve(`${templatesDir}/${tmpl.path}`);
+ return acc;
+ }, {});
+
+/* istanbul ignore next */
+/**
+ * Returns an object containing templates and requirables created by
+ * combining the given template and content parameters.
+ * @param {array} templates - An array of templates.
+ * @param {string} templatesDir - The path to the template directory.
+ * @param {string} contentDir - The path to the content directory.
+ */
+const parseRequirements = (templates, templatesDir, contentDir) => ({
+ templates: parseTemplates(templates, templatesDir),
+ requirables: parseRequirables(contentDir),
+});
+
+export default parseRequirements;
diff --git a/src/build/parsers/parseRequirables.test.js b/src/gatsby/parseRequirements.test.js
similarity index 77%
rename from src/build/parsers/parseRequirables.test.js
rename to src/gatsby/parseRequirements.test.js
index d5464fd42..1f62b483f 100644
--- a/src/build/parsers/parseRequirables.test.js
+++ b/src/gatsby/parseRequirements.test.js
@@ -1,4 +1,4 @@
-import parseRequirables from './parseRequirables';
+import { parseRequirables, parseTemplates } from './parseRequirements';
import glob from 'glob';
import path from 'path';
@@ -6,6 +6,18 @@ import path from 'path';
jest.mock('glob');
jest.mock('path');
+
+const templates = [
+ {
+ 'name': 'SnippetPage',
+ 'path': 'snippetPage/index.jsx',
+ },
+ {
+ 'name': 'SearchPage',
+ 'path': 'searchPage/index.jsx',
+ },
+];
+
const mockRequirables = {
'stdRequirable': {
meta: {
@@ -66,10 +78,18 @@ jest.mock('ltdRequirable.json',
describe('parseRequirables', () => {
it('returns the array of the resulting requirables', () => {
- console.log();
expect(parseRequirables('my-content-dir')).toEqual([
{...mockRequirables['stdRequirable'], context: mockRequirables['stdRequirable'] },
{...mockRequirables['ltdRequirable'], context: mockRequirables['ltdRequirable']},
]);
});
});
+
+describe('parseTemplates', () => {
+ it('returns an object with the appropriate structure and data', () => {
+ expect(parseTemplates(templates, 'my-templates-dir')).toEqual({
+ 'SnippetPage': 'my-templates-dir/snippetPage/index.jsx',
+ 'SearchPage': 'my-templates-dir/searchPage/index.jsx',
+ });
+ });
+});
From 08caa34904b52b9f6d1fa717191fad79f471cf48 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 22:58:05 +0300
Subject: [PATCH 17/39] Simplify parseRequirements API
Minimize logic in gatsby-node.
---
gatsby-node.js | 10 +---------
src/gatsby/parseRequirements.js | 19 +++++++++++--------
2 files changed, 12 insertions(+), 17 deletions(-)
diff --git a/gatsby-node.js b/gatsby-node.js
index 97a72760e..8a3df2bc5 100644
--- a/gatsby-node.js
+++ b/gatsby-node.js
@@ -1,20 +1,12 @@
const { green } = require('chalk');
-const env = require('./.build/env').default;
-
const {
createPages,
onCreateWebpackConfig,
parseRequirements,
} = require(`./src/gatsby`);
-const paths = require(`./src/config/paths`);
-const { requirables, templates} = parseRequirements(
- env === 'DEVELOPMENT' ? paths.devTemplates : paths.templates,
- paths.templatesPath,
- paths.contentPath
-);
+const { requirables, templates} = parseRequirements();
console.log(`${green('success')} parse requirements`);
exports.createPages = createPages(templates, requirables);
-
exports.onCreateWebpackConfig = onCreateWebpackConfig;
diff --git a/src/gatsby/parseRequirements.js b/src/gatsby/parseRequirements.js
index bd8cf6e01..55ee63e80 100644
--- a/src/gatsby/parseRequirements.js
+++ b/src/gatsby/parseRequirements.js
@@ -1,5 +1,9 @@
import glob from 'glob';
import path from 'path';
+import paths from 'config/paths';
+
+/* istanbul ignore next */
+const isDevelopment = process.env.NODE_ENV.toLowerCase() === 'development';
/**
* Combines the given data JSONs, using the data files
@@ -27,15 +31,14 @@ export const parseTemplates = (templates, templatesDir) =>
/* istanbul ignore next */
/**
- * Returns an object containing templates and requirables created by
- * combining the given template and content parameters.
- * @param {array} templates - An array of templates.
- * @param {string} templatesDir - The path to the template directory.
- * @param {string} contentDir - The path to the content directory.
+ * Returns an object containing templates and requirables.
*/
-const parseRequirements = (templates, templatesDir, contentDir) => ({
- templates: parseTemplates(templates, templatesDir),
- requirables: parseRequirables(contentDir),
+const parseRequirements = () => ({
+ templates: parseTemplates(
+ isDevelopment ? paths.devTemplates : paths.templates,
+ paths.templatesPath
+ ),
+ requirables: parseRequirables(paths.contentPath),
});
export default parseRequirements;
From 8be32e8a05bb1517800e64356b2a9dd9984298f5 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 23:33:33 +0300
Subject: [PATCH 18/39] Add search page to extracted data
---
src/yild/extractSnippets/index.js | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/yild/extractSnippets/index.js b/src/yild/extractSnippets/index.js
index ed35aab8e..d6b885f65 100644
--- a/src/yild/extractSnippets/index.js
+++ b/src/yild/extractSnippets/index.js
@@ -3,6 +3,7 @@ import { initAction, loadContentConfigs } from '../core';
import extract from './extract';
import postProcess from './postProcess';
import literals from 'lang/en';
+import { transformSnippetIndex } from 'build/transformers';
const extractSnippets = async() => {
const [boundLog, , inPath, outPath] = initAction('extractSnippets', [
@@ -28,7 +29,9 @@ const extractSnippets = async() => {
await Promise
.all(extract(configs, langData, boundLog))
.then(res => { allData = res; });
- const allSnippetData = allData.reduce((acc, r) => [...acc, ...r.data.data], []);
+ const allSnippetData = allData
+ .reduce((acc, r) => [...acc, ...r.data.data], [])
+ .sort((a, b) => b.ranking - a.ranking);
boundLog(`Extracted data for ${allSnippetData.length} snippets`, 'success');
boundLog('Post-processing snippet data', 'info');
@@ -62,6 +65,16 @@ const extractSnippets = async() => {
template: 'SettingsPage',
priority: 0.01,
},
+ {
+ slug: '/search',
+ context: {
+ searchIndex: transformSnippetIndex(allSnippetData, true),
+ recommendedSnippets: transformSnippetIndex(allSnippetData.slice(0, 3)),
+ pageDescription: literals.search.pageDescription(allSnippetData.length),
+ },
+ template: 'SearchPage',
+ priority: 0.25,
+ },
].forEach(p => {
const outDir = `${outPath}${p.slug}`;
fs.ensureDirSync(outDir);
From c03dbe420e8d70a7f007fc3fd083b9217f5b26bf Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 23:41:22 +0300
Subject: [PATCH 19/39] Introduce .env files
Used for environment variables. More:
https://www.gatsbyjs.com/docs/environment-variables
---
.env.development | 1 +
.env.production | 1 +
2 files changed, 2 insertions(+)
create mode 100644 .env.development
create mode 100644 .env.production
diff --git a/.env.development b/.env.development
new file mode 100644
index 000000000..d3ccabf50
--- /dev/null
+++ b/.env.development
@@ -0,0 +1 @@
+ENV=development
diff --git a/.env.production b/.env.production
new file mode 100644
index 000000000..4fdbe6fb6
--- /dev/null
+++ b/.env.production
@@ -0,0 +1 @@
+ENV=production
From d3f2fe2c873dbd0c7142700b71182c3392c1e890 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 23:42:03 +0300
Subject: [PATCH 20/39] Deprecate env file
Use .env files, instead. Deprecate yild preparation code.
---
package.json | 10 ++---
src/components/organisms/shell/index.jsx | 3 +-
src/components/organisms/shell/index.test.jsx | 2 -
src/yild/core/actions.js | 10 -----
src/yild/index.js | 5 +--
src/yild/prepareEnv/index.js | 42 -------------------
6 files changed, 8 insertions(+), 64 deletions(-)
delete mode 100644 src/yild/prepareEnv/index.js
diff --git a/package.json b/package.json
index 8df0d3f27..e2f07df9d 100644
--- a/package.json
+++ b/package.json
@@ -70,13 +70,13 @@
"scripts": {
"extract-snippets": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -e",
"watch-snippets": "npm-watch extract-snippets",
- "prepare-assets": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -e -n=DEVELOPMENT",
+ "prepare-assets": "NODE_PATH=src NODE_ENV=development npx --node-arg '-r esm' ./src/jobs/yild.js -e ",
"watch-assets": "npm-watch prepare-assets",
- "serve-snippets": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -n=DEVELOPMENT -s",
+ "serve-snippets": "NODE_PATH=src NODE_ENV=development npx --node-arg '-r esm' ./src/jobs/yild.js -s",
"yild": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js",
- "prebuild": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -u -a -e -i -n=PRODUCTION -c",
- "predevelop": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -n=DEVELOPMENT -c",
- "pretest": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -n=DEVELOPMENT -c",
+ "prebuild": "NODE_PATH=src NODE_ENV=production npx --node-arg '-r esm' ./src/jobs/yild.js -u -a -e -i -c",
+ "predevelop": "NODE_PATH=src NODE_ENV=development npx --node-arg '-r esm' ./src/jobs/yild.js -c",
+ "pretest": "NODE_PATH=src NODE_ENV=test npx --node-arg '-r esm' ./src/jobs/yild.js -c",
"build": "NODE_PATH=src npx --node-arg '-r esm' gatsby build",
"develop": "NODE_PATH=src npx --node-arg '-r esm' gatsby develop -p 8000",
"debug": "NODE_PATH=src npx --node-arg '-r esm --nolazy --inspect-brk' node_modules/.bin/gatsby develop",
diff --git a/src/components/organisms/shell/index.jsx b/src/components/organisms/shell/index.jsx
index e8507732e..f807723e3 100644
--- a/src/components/organisms/shell/index.jsx
+++ b/src/components/organisms/shell/index.jsx
@@ -6,7 +6,6 @@ import Footer from 'components/molecules/footer';
import CookieConsentPopup from 'components/molecules/cookieConsentPopup';
import literals from 'lang/en/client/common';
import { combineClassNames } from 'utils';
-import env from '../../../../.build/env';
const propTypes = {
children: PropTypes.oneOfType([
@@ -64,7 +63,7 @@ const Shell = ({
{
- typeof acceptsCookies === 'undefined' && env === 'PRODUCTION' && !isBot ?
+ typeof acceptsCookies === 'undefined' && process.env.ENV !== 'development' && !isBot ?
: null
}
diff --git a/src/components/organisms/shell/index.test.jsx b/src/components/organisms/shell/index.test.jsx
index 53f2e6656..1a906b46d 100644
--- a/src/components/organisms/shell/index.test.jsx
+++ b/src/components/organisms/shell/index.test.jsx
@@ -3,7 +3,6 @@ import { cleanup } from '@testing-library/react';
import { renderConnected } from 'test/utils';
import Shell from './index';
import { toggleDarkMode } from 'state/shell';
-import * as env from '../../../../.build/env';
describe(' ', () => {
let wrapper, pageContainer, store, rerender;
@@ -77,7 +76,6 @@ describe(' ', () => {
describe('when in production without cookies enabled', () => {
beforeEach(() => {
- env.default = 'PRODUCTION';
wrapper = rerender(
{ innerText }
diff --git a/src/yild/core/actions.js b/src/yild/core/actions.js
index 50d16edd4..d216c1ccd 100644
--- a/src/yild/core/actions.js
+++ b/src/yild/core/actions.js
@@ -1,10 +1,8 @@
-import { format } from '../logOutput';
import prepareAssets from '../prepareAssets';
import extractSnippets from '../extractSnippets';
import serveSnippets from '../serveSnippets';
import updateContent from '../updateContent';
import makeIcons from '../makeIcons';
-import prepareEnv from '../prepareEnv';
import prepareCacheKey from '../prepareCacheKey';
// Keep this in a variable to allow for help to run the way it should.
@@ -45,14 +43,6 @@ const actions = {
step: 0,
matcher: /^-{0,2}i(cons)?$/gi,
},
- 'environment': {
- description: `generate environment configuration file\n${format('ENV', 'green', 'bold')} can be one of: (DEVELOPMENT, PRODUCTION)`,
- process: prepareEnv,
- step: 0,
- matcher: /^-(n)|(-environment)=.*$/gi,
- key: { short: 'n', long: 'environment' },
- param: 'ENV',
- },
'cache': {
description: `generate cache key file`,
process: prepareCacheKey,
diff --git a/src/yild/index.js b/src/yild/index.js
index 22eb1a827..bfd0f13f2 100644
--- a/src/yild/index.js
+++ b/src/yild/index.js
@@ -25,11 +25,10 @@ const performStepActions = (actions, config) => stepNo =>
* @param {object} config - A configuration object.
*/
const yild = async config => {
+ console.log(process.env.NODE_ENV);
global._yild_instance = {
config,
- env: config.args.indexOf('DEVELOPMENT') !== -1
- ? 'DEVELOPMENT'
- : 'PRODUCTION',
+ env: process.env.NODE_ENV.toUpperCase(),
};
logger.log(`${format('yild', 'bold')} is starting up...`, 'info');
diff --git a/src/yild/prepareEnv/index.js b/src/yild/prepareEnv/index.js
deleted file mode 100644
index 15cbef636..000000000
--- a/src/yild/prepareEnv/index.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import fs from 'fs-extra';
-import path from 'path';
-import { initAction } from '../core';
-import { format } from '../logOutput';
-
-const VALID_PARAM_VALUES = ['PRODUCTION', 'DEVELOPMENT'];
-
-/**
- * Generates the environment configuration file.
- * @param {string} param - 'DEVELOPMENT' or 'PRODUCTION', used for environment configuration.
- */
-const prepareEnv = async param => {
- const [boundLog, , outPath] = initAction('prepareEnv', [['paths', 'buildPath']]);
- boundLog('Generating environment configuration file...', 'info');
-
- let envMode = VALID_PARAM_VALUES.includes(param) ? param : VALID_PARAM_VALUES[0];
- if(!VALID_PARAM_VALUES.includes(param)) {
- boundLog(
- `Parameter value ${format(param, 'bold')} is invalid, defaulting to ${format(envMode, 'bold')}`,
- 'warning'
- );
- } else {
- boundLog(
- `Using parameter value ${format(param, 'bold')}`,
- 'info'
- );
- }
-
- boundLog(`Writing environment configuration file to ${path.resolve(outPath, 'env.js')}`, 'info');
- const fileData = [
- `const env = '${envMode}';`,
- 'export default env;',
- ].join('\n');
-
- fs.ensureDirSync(outPath);
- await fs.writeFile(path.resolve(outPath, 'env.js'), fileData);
- boundLog('Environment configuration file generated', 'success');
-
- return;
-};
-
-export default prepareEnv;
From 913f986e67df057dd437f70a1f23074f249b0a9a Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 26 Aug 2020 23:47:37 +0300
Subject: [PATCH 21/39] Deprecate cacheKey file
Use environment variables instead. Allow for manual bumping
whenever necessary. Distinguish between development and
production to allow for easier debugging in dev mode.
---
.env.development | 1 +
.env.production | 1 +
package.json | 6 +++---
src/state/shell.js | 6 ++----
src/yild/core/actions.js | 7 -------
src/yild/index.js | 1 -
src/yild/prepareCacheKey/index.js | 26 --------------------------
7 files changed, 7 insertions(+), 41 deletions(-)
delete mode 100644 src/yild/prepareCacheKey/index.js
diff --git a/.env.development b/.env.development
index d3ccabf50..239142da6 100644
--- a/.env.development
+++ b/.env.development
@@ -1 +1,2 @@
ENV=development
+CACHE_KEY=dev_2020_08
diff --git a/.env.production b/.env.production
index 4fdbe6fb6..7309ce789 100644
--- a/.env.production
+++ b/.env.production
@@ -1 +1,2 @@
ENV=production
+CACHE_KEY=30swp20200826234402
diff --git a/package.json b/package.json
index e2f07df9d..78a1854e4 100644
--- a/package.json
+++ b/package.json
@@ -74,9 +74,9 @@
"watch-assets": "npm-watch prepare-assets",
"serve-snippets": "NODE_PATH=src NODE_ENV=development npx --node-arg '-r esm' ./src/jobs/yild.js -s",
"yild": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js",
- "prebuild": "NODE_PATH=src NODE_ENV=production npx --node-arg '-r esm' ./src/jobs/yild.js -u -a -e -i -c",
- "predevelop": "NODE_PATH=src NODE_ENV=development npx --node-arg '-r esm' ./src/jobs/yild.js -c",
- "pretest": "NODE_PATH=src NODE_ENV=test npx --node-arg '-r esm' ./src/jobs/yild.js -c",
+ "prebuild": "NODE_PATH=src NODE_ENV=production npx --node-arg '-r esm' ./src/jobs/yild.js -u -a -e -i",
+ "predevelop": "NODE_PATH=src NODE_ENV=development npx --node-arg '-r esm' ./src/jobs/yild.js",
+ "pretest": "NODE_PATH=src NODE_ENV=test npx --node-arg '-r esm' ./src/jobs/yild.js",
"build": "NODE_PATH=src npx --node-arg '-r esm' gatsby build",
"develop": "NODE_PATH=src npx --node-arg '-r esm' gatsby develop -p 8000",
"debug": "NODE_PATH=src npx --node-arg '-r esm --nolazy --inspect-brk' node_modules/.bin/gatsby develop",
diff --git a/src/state/shell.js b/src/state/shell.js
index 16369061c..c913c579d 100644
--- a/src/state/shell.js
+++ b/src/state/shell.js
@@ -1,5 +1,3 @@
-import cacheKey from '../../.build/cacheKey';
-
/** Checks if the client is a bot */
const isBot = () =>
typeof navigator !== 'undefined' &&
@@ -10,8 +8,8 @@ const isBot = () =>
const initialState = {
isDarkMode: undefined,
hasGithubLinksEnabled: undefined,
- cacheKey,
- newCacheKey: cacheKey,
+ cacheKey: process.env.CACHE_KEY,
+ newCacheKey: process.env.CACHE_KEY,
isBot: isBot(),
acceptsCookies: undefined,
};
diff --git a/src/yild/core/actions.js b/src/yild/core/actions.js
index d216c1ccd..3d10e3e1c 100644
--- a/src/yild/core/actions.js
+++ b/src/yild/core/actions.js
@@ -3,7 +3,6 @@ import extractSnippets from '../extractSnippets';
import serveSnippets from '../serveSnippets';
import updateContent from '../updateContent';
import makeIcons from '../makeIcons';
-import prepareCacheKey from '../prepareCacheKey';
// Keep this in a variable to allow for help to run the way it should.
export const helpFlag = /^-{0,2}h(elp)?$/gi;
@@ -43,12 +42,6 @@ const actions = {
step: 0,
matcher: /^-{0,2}i(cons)?$/gi,
},
- 'cache': {
- description: `generate cache key file`,
- process: prepareCacheKey,
- step: 0,
- matcher: /^-{0,2}c(ache)?$/gi,
- },
'serve': {
description: 'serve snippets from the generated JSON files',
process: serveSnippets,
diff --git a/src/yild/index.js b/src/yild/index.js
index bfd0f13f2..6f5638622 100644
--- a/src/yild/index.js
+++ b/src/yild/index.js
@@ -25,7 +25,6 @@ const performStepActions = (actions, config) => stepNo =>
* @param {object} config - A configuration object.
*/
const yild = async config => {
- console.log(process.env.NODE_ENV);
global._yild_instance = {
config,
env: process.env.NODE_ENV.toUpperCase(),
diff --git a/src/yild/prepareCacheKey/index.js b/src/yild/prepareCacheKey/index.js
deleted file mode 100644
index df452165b..000000000
--- a/src/yild/prepareCacheKey/index.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import fs from 'fs-extra';
-import path from 'path';
-import { initAction } from '../core';
-
-/**
- * Generates the cache key file.
- */
-const prepareCacheKey = async() => {
- const [boundLog, , outPath] = initAction('prepareCacheKey', [['paths', 'buildPath']]);
- boundLog('Generating cache key file...', 'info');
-
- boundLog(`Writing cache key file to ${path.resolve(outPath, 'cacheKey.js')}`, 'info');
- const fileData = [
- `const cacheKey = '${+new Date()}';`,
- 'export default cacheKey;',
- ].join('\n');
-
- fs.ensureDirSync(outPath);
- await fs.writeFile(path.resolve(outPath, 'cacheKey.js'), fileData);
- boundLog('Cache key file generated', 'success');
-
- return;
-
-};
-
-export default prepareCacheKey;
From 81af1f1ab03eff87f4a8f5815a58e66ecf961b66 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 2 Sep 2020 15:52:27 +0300
Subject: [PATCH 22/39] Create build utilities for JSON files
---
src/build/json/index.js | 43 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 src/build/json/index.js
diff --git a/src/build/json/index.js b/src/build/json/index.js
new file mode 100644
index 000000000..5d2a6fd78
--- /dev/null
+++ b/src/build/json/index.js
@@ -0,0 +1,43 @@
+import util from 'util';
+import fs from 'fs-extra';
+
+const writeFile = util.promisify(fs.writeFile);
+const routePrefix = 'https://30secondsofcode.org';
+
+/**
+ * Writes the provided chunks to the specified directory.
+ * If the directory does not exist, it will be created.
+ * Displays a warning, if there are multiple chunks without one named `index`.
+ * @param {string} path - Directory path to write the chunks.
+ * @param {Array} dataChunkPairs - A 2D array of key-value ([string, object]) pairs.
+ * @returns {Promise} - A promise that resolves as soon as all chunks are written
+ */
+export const writeChunks = (path, ...dataChunkPairs) => {
+ fs.ensureDirSync(path);
+ if (!dataChunkPairs > 1 && !dataChunkPairs.some(dcp => dcp[0] === 'index'))
+ console.warn(`Data for ${path} does not contain an index!`);
+
+ return Promise.all(
+ dataChunkPairs.map(([key, value]) =>
+ writeFile(`${path}/${key}.json`, JSON.stringify(value, null, 2))
+ )
+ );
+};
+
+/**
+ * Creates the bare minimum for an index chunk.
+ * @param {string} path - Relative path for the chunk (e.g. `/404`).
+ * @param {string} template - Name of the template to be used.
+ * @param {number} priority - A value between 0.0 and 1.0 (default 0.5)
+ */
+export const createIndexChunk = (path, template, priority = 0.5) => {
+ const relRoute = path.startsWith('/') ? path : `/${path}`;
+ return {
+ template, relRoute, fullRoute: `${routePrefix}${relRoute}`, priority,
+ };
+};
+
+export default {
+ writeChunks,
+ createIndexChunk,
+};
From ad963517973d0db392bdc5c0c1b4073a3e2c5acb Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 2 Sep 2020 15:52:55 +0300
Subject: [PATCH 23/39] Create build utilities for config files
---
src/build/config/content.js | 85 +++++++++++++++++++++++++++++++++++++
src/build/config/index.js | 6 +++
2 files changed, 91 insertions(+)
create mode 100644 src/build/config/content.js
create mode 100644 src/build/config/index.js
diff --git a/src/build/config/content.js b/src/build/config/content.js
new file mode 100644
index 000000000..aeb8f19af
--- /dev/null
+++ b/src/build/config/content.js
@@ -0,0 +1,85 @@
+import path from 'path';
+import glob from 'glob';
+// TODO: Consider parsing this via a new parser or similar
+// The argument against is that it's a single case and might not extend to other repos in the future
+import authors from '../../../content/sources/30blog/blog_data/blog_authors';
+
+/**
+ * Enriches the content configuration objects with additional attributes.
+ * @param {Array} configs - An array of configuration objects.
+ * @param {Array} langData - An array of language data objects.
+ */
+export const getRichConfigs = (configs, langData) => configs.map(cfg => {
+ const {
+ contentPath: contentOutDir,
+ staticAssetPath: assetDir,
+ } = global._yild_instance.config.paths;
+
+ const assetPath = `/${assetDir}/`;
+ cfg.assetPath = assetPath;
+ cfg.outPath = contentOutDir;
+ cfg.langData = langData;
+
+ const isBlog = Boolean(cfg.isBlog);
+ cfg.commonData = {
+ blog: isBlog,
+ language: cfg.language || {},
+ };
+ cfg.slugPrefix = `${cfg.slug}/s`;
+ cfg.repoUrlPrefix = `${cfg.repoUrl}/blob/master/${cfg.snippetPath}`;
+
+ let otherLanguages = [];
+ if (cfg.secondLanguage) otherLanguages.push(cfg.secondLanguage);
+ if (cfg.optionalLanguage) otherLanguages.push(cfg.optionalLanguage);
+ if (otherLanguages.length) cfg.commonData.language.otherLanguages = otherLanguages;
+ if (!cfg.cardTemplate) cfg.cardTemplate = 'StandardSnippetCard';
+
+ cfg.isCssSnippet = cfg.dirName === '30css';
+ cfg.isBlogSnippet = isBlog;
+ cfg.hasOptionalLanguage = !cfg.isCssSnippet && !isBlog
+ && cfg.optionalLanguage && cfg.optionalLanguage.short;
+ cfg.languages = isBlog ? [] : [
+ cfg.language.short,
+ cfg.isCssSnippet ? cfg.secondLanguage.short : null,
+ cfg.hasOptionalLanguage || cfg.isCssSnippet ? cfg.optionalLanguage.short : null,
+ ].filter(Boolean).join('|');
+ cfg.authors = !isBlog ? [] : authors;
+
+ cfg.icon = cfg.theme ? cfg.theme.iconName : null;
+ cfg.sourceDir = `${cfg.dirName}/${cfg.snippetPath}`;
+ return cfg;
+});
+
+/**
+ * Loads and enriches the content configuration files.
+ * Will use stored ones, if they exist.
+ * @param {string} inPath - Name of the directory where the configs are located.
+ * @param {logger} boundLog - A bound logger.log function.
+ * @returns {array} - An array of content configs.
+ */
+export const loadContentConfigs = (inPath, boundLog) => {
+ boundLog(`Loading individual configuration files in ${path.resolve(inPath, 'configs')}`, 'info');
+ let configs = [];
+ if(global._yild_instance.contentConfigs) {
+ configs = global._yild_instance.contentConfigs;
+ boundLog(`Using already loaded configuration files`, 'success');
+ } else {
+ const rawConfigs = glob.sync(`${inPath}/configs/*.json`)
+ .map( file => require(path.resolve(file)));
+ const langData = rawConfigs
+ .filter(cfg =>
+ cfg.language && cfg.language.long &&
+ cfg.theme && cfg.theme.iconName
+ )
+ .map(cfg => ({
+ language: cfg.language.long.toLowerCase(),
+ icon: cfg.theme.iconName,
+ }));
+ boundLog(`Processed data for ${langData.length} languages`, 'success');
+ configs = getRichConfigs(rawConfigs, langData);
+
+ global._yild_instance.contentConfigs = configs;
+ boundLog(`Loaded ${configs.length} configuration files`, 'success');
+ }
+ return configs;
+};
diff --git a/src/build/config/index.js b/src/build/config/index.js
new file mode 100644
index 000000000..ba34f8d50
--- /dev/null
+++ b/src/build/config/index.js
@@ -0,0 +1,6 @@
+import { loadContentConfigs, getRichConfigs } from './content';
+
+export {
+ loadContentConfigs,
+ getRichConfigs
+};
From 6a39717bd944f47f17be77a0e6b7c1761be462a3 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 2 Sep 2020 15:53:09 +0300
Subject: [PATCH 24/39] Create build utilities for listings
---
src/build/listing/index.js | 248 +++++++++++++++++++++++++++++++++++++
1 file changed, 248 insertions(+)
create mode 100644 src/build/listing/index.js
diff --git a/src/build/listing/index.js b/src/build/listing/index.js
new file mode 100644
index 000000000..ad9bd2093
--- /dev/null
+++ b/src/build/listing/index.js
@@ -0,0 +1,248 @@
+import { transformSnippetIndex } from 'build/transformers';
+import { chunk } from 'utils';
+import EXPERTISE_LEVELS from 'config/expertise';
+import literals from 'lang/en/listing';
+import { createIndexChunk, writeChunks } from 'build/json';
+
+const ORDERS_MAP = {
+ 'p': literals.orders.popularity,
+ 'a': literals.orders.alphabetical,
+ 'e': literals.orders.expertise,
+};
+
+const CARDS_PER_PAGE = 40;
+
+export const compileListingPages = async(
+ chunks,
+ context,
+ baseUrl,
+ slugOrderingSegment,
+ ordersList
+) => {
+ const {
+ contentPath: contentOutDir,
+ } = global._yild_instance.config.paths;
+
+ for (let [i, chunk] of chunks.entries()) {
+ const isPopularityOrdered = slugOrderingSegment === 'p';
+ const isFirstPage = isPopularityOrdered && i === 0;
+ const isMainListing = context.listingType === 'main' && isPopularityOrdered;
+ const isMainListingFirstPage = isMainListing && isFirstPage;
+ const isTopLevelListing = (context.listingType === 'language' || context.listingType === 'blog') && isPopularityOrdered;
+ const isTopLevelListingFirstPage = isTopLevelListing && isFirstPage;
+ const isMainTagListing = context.listingType === 'tag' && isFirstPage;
+ const priority = isMainListingFirstPage ? 1.0
+ : (isTopLevelListingFirstPage || isMainListing) ? 0.9
+ : (isMainTagListing || isTopLevelListing) ? 0.8
+ : 0.7;
+ const outDir = `${contentOutDir}${baseUrl}/${slugOrderingSegment}/${i + 1}`;
+
+ await writeChunks(
+ outDir,
+ ['index',
+ createIndexChunk(`${baseUrl}/${slugOrderingSegment}/${i + 1}`, 'ListingPage', priority),
+ ],
+ ['snippetList', { snippetList: chunk }],
+ ['metadata', {
+ isMainListing,
+ paginator: {
+ pageNumber: i + 1,
+ totalPages: chunks.length,
+ baseUrl,
+ slugOrderingSegment,
+ },
+ sorter: {
+ orders: ordersList.map(order => (
+ {
+ url: `${baseUrl}/${order}/1`,
+ title: ORDERS_MAP[order],
+ }
+ )),
+ selectedOrder: ORDERS_MAP[slugOrderingSegment],
+ },
+ ...context,
+ }]
+ );
+ }
+};
+
+export const compileListingPagesWithOrderOptions = async(
+ context,
+ baseUrl,
+ orders,
+ chunks,
+ contextCustomizer = () => ({})
+) => {
+ for (let [i, order] of orders.entries()) {
+ await compileListingPages(
+ chunks[i],
+ { ...context, ...contextCustomizer(order, i)},
+ baseUrl,
+ order,
+ orders
+ );
+ }
+};
+
+/**
+ * Write data for listings to appropriate JSON files.
+ * @param {Array} snippetIndex - The array of indexed snippets.
+ * @param {Array} listingMetas - An array of listing metadata objects.
+ */
+export const compileListingData = async(snippetIndex, listingMetas) => {
+ // 1. Create listing pages for the main listing:
+ // Tranform and chunk data for popularity, alphabetical and expertise ordering
+ const transformedIndex = transformSnippetIndex(snippetIndex);
+ const popularChunks = chunk(transformedIndex, CARDS_PER_PAGE);
+ const alphabeticalChunks = chunk(transformedIndex.sort((a, b) =>
+ a.title.localeCompare(b.title)
+ ), CARDS_PER_PAGE);
+ const expertiseChunks = chunk(transformedIndex.sort((a, b) =>
+ a.expertise === b.expertise ? a.title.localeCompare(b.title) :
+ !a.expertise ? 1 : !b.expertise ? -1 :
+ EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
+ ), CARDS_PER_PAGE);
+ // Create main listing sublinks and customization method for context
+ const mainListingSublinks = listingMetas
+ .map(v => v.featured > 0 ? v : {...v, featured: 500 })
+ .sort((a, b) => a.featured === b.featured ? a.name - b.name : a.featured - b.featured);
+ const mainContextCustomizer = order => {
+ return {
+ listingSublinks: mainListingSublinks
+ .map(l => ({
+ ...l,
+ url: l.url.replace('/p/1', `/${order}/1`),
+ })),
+ };
+ };
+ // Create the listing pages with the order options provided
+ await compileListingPagesWithOrderOptions(
+ {
+ listingName: literals.snippetList,
+ listingTitle: literals.snippetList,
+ listingType: 'main',
+ listingSublinks: mainListingSublinks,
+ pageDescription: literals.pageDescription('main', {
+ snippetCount: transformedIndex.length,
+ }),
+ },
+ '/list',
+ ['p', 'a', 'e'],
+ [popularChunks, alphabeticalChunks, expertiseChunks],
+ mainContextCustomizer
+ );
+
+ // 2. Create listing pages for the language listings
+ for (let listingMeta of listingMetas) {
+ // Determine slug prefix and relevant information, create chunks from data for
+ // each of the ordering options
+ const slugPrefix = listingMeta.slugPrefix;
+ const snippetIndexName = snippetIndex
+ .find(s => s.slug.startsWith(`${slugPrefix}`)).language.long || '';
+ const snippetIndexSlugData = snippetIndex.filter(s =>
+ s.slug.startsWith(`${slugPrefix}`) ||
+ (s.blog && s.tags.all.find(t => t.toLowerCase() === snippetIndexName.toLowerCase()))
+ );
+ const transformedSlugChunks = transformSnippetIndex(snippetIndexSlugData);
+ const popularSlugChunks = chunk(transformedSlugChunks, CARDS_PER_PAGE);
+ const alphabeticalSlugChunks = chunk(transformedSlugChunks.sort((a, b) =>
+ a.title.localeCompare(b.title)
+ ), CARDS_PER_PAGE);
+ const expertiseSlugChunks = chunk(transformedSlugChunks.sort((a, b) =>
+ a.expertise === b.expertise ? a.title.localeCompare(b.title) :
+ !a.expertise ? 1 : !b.expertise ? -1 :
+ EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
+ ), CARDS_PER_PAGE);
+ // Determine tag prefixes for the listing
+ const snippetIndexTagPrefixes = listingMeta.tags;
+ const slugContextCustomizer = order => {
+ return {
+ listingSublinks: listingMeta.blog ? [] : [
+ {
+ url: `${slugPrefix}/${order}/1`,
+ name: literals.tag('all'),
+ selected: true,
+ },
+ ...listingMeta.tags
+ .map(tag => ({
+ url: `${slugPrefix}/t/${tag}/${order}/1`,
+ name: literals.tag(tag),
+ })),
+ ],
+ };
+ };
+ // Create the listing pages with the order options provided
+ await compileListingPagesWithOrderOptions(
+ {
+ listingName: listingMeta.blog ? literals.blog : literals.codelang(snippetIndexName),
+ listingTitle: listingMeta.blog ? literals.blog : literals.codelang(snippetIndexName),
+ listingType: listingMeta.blog ? 'blog' : 'language',
+ pageDescription: literals.pageDescription(listingMeta.blog ? 'blog' : 'language', {
+ snippetCount: snippetIndexSlugData.length,
+ listingLanguage: listingMeta.blog ? 'blog' : snippetIndexName,
+ }),
+ },
+ `${slugPrefix}`,
+ ['p', 'a', 'e'],
+ [popularSlugChunks, alphabeticalSlugChunks, expertiseSlugChunks],
+ slugContextCustomizer
+ );
+
+
+ for(let tagPrefix of snippetIndexTagPrefixes) {
+ // Determine slug prefix and relevant information, create chunks from data
+ // for each of the ordering options
+ const snippetIndexTagData = snippetIndex
+ .filter(s =>
+ s.tags.primary === tagPrefix && s.slug.startsWith(`${slugPrefix}`) ||
+ ( s.blog &&
+ s.tags.all.find(t => t.toLowerCase() === snippetIndexName.toLowerCase()) &&
+ s.tags.all.find(t => t.toLowerCase() === tagPrefix.toLowerCase())
+ )
+ );
+ const transformedTagChunks = transformSnippetIndex(snippetIndexTagData);
+ const popularTagChunks = chunk(transformedTagChunks, CARDS_PER_PAGE);
+ const alphabeticalTagChunks = chunk(transformedTagChunks.sort((a, b) =>
+ a.title.localeCompare(b.title)
+ ), CARDS_PER_PAGE);
+ const expertiseTagChunks = chunk(transformedTagChunks.sort((a, b) =>
+ a.expertise === b.expertise ? a.title.localeCompare(b.title) :
+ !a.expertise ? 1 : !b.expertise ? -1 :
+ EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
+ ), CARDS_PER_PAGE);
+ const tagContextCustomizer = order => {
+ return {
+ listingSublinks: listingMeta.blog ? [] : [
+ {
+ url: `${slugPrefix}/${order}/1`,
+ name: literals.tag('all'),
+ selected: true,
+ },
+ ...listingMeta.tags
+ .map(tag => ({
+ url: `${slugPrefix}/t/${tag}/${order}/1`,
+ name: literals.tag(tag),
+ })),
+ ].map(tag => ({ ...tag, selected: tag.url.indexOf(`/t/${tagPrefix}/`) !== -1 })),
+ };
+ };
+ // Create the listing pages with the order options provided
+ await compileListingPagesWithOrderOptions(
+ {
+ listingName: literals.codelangTag(snippetIndexName, tagPrefix),
+ listingTitle: literals.codelang(snippetIndexName),
+ listingType: 'tag',
+ pageDescription: literals.pageDescription('tag', {
+ snippetCount: snippetIndexTagData.length,
+ listingLanguage: snippetIndexName,
+ listingTag: tagPrefix,
+ }),
+ },
+ `${slugPrefix}/t/${tagPrefix}`,
+ ['p', 'a', 'e'],
+ [popularTagChunks, alphabeticalTagChunks, expertiseTagChunks],
+ tagContextCustomizer
+ );
+ }
+ }
+};
From d56537dc61ce2103d88fbcaf617fb0590b95c572 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 2 Sep 2020 15:53:20 +0300
Subject: [PATCH 25/39] Create build utilities for snippets
---
src/build/snippet/compileSnippet.js | 164 +++++++++++++++++++++++++++
src/build/snippet/index.js | 25 +++++
src/build/snippet/parseMarkdown.js | 168 ++++++++++++++++++++++++++++
src/build/snippet/readSnippets.js | 34 ++++++
src/build/snippet/snippetData.js | 145 ++++++++++++++++++++++++
5 files changed, 536 insertions(+)
create mode 100644 src/build/snippet/compileSnippet.js
create mode 100644 src/build/snippet/index.js
create mode 100644 src/build/snippet/parseMarkdown.js
create mode 100644 src/build/snippet/readSnippets.js
create mode 100644 src/build/snippet/snippetData.js
diff --git a/src/build/snippet/compileSnippet.js b/src/build/snippet/compileSnippet.js
new file mode 100644
index 000000000..22b40372c
--- /dev/null
+++ b/src/build/snippet/compileSnippet.js
@@ -0,0 +1,164 @@
+import tokenizeSnippet from 'engines/searchIndexingEngine';
+import { convertToSeoSlug, uniqueElements } from 'utils';
+import {
+ determineExpertiseFromTags,
+ stripExpertiseFromTags,
+ transformSnippetContext,
+ transformBreadcrumbs,
+ transformSnippetDescription
+} from 'build/transformers';
+import rankSnippet from 'engines/rankingEngine';
+import {
+ getData,
+ getCodeBlocks,
+ getTextualContent,
+ getGitMetadata,
+ getTags,
+ getId
+} from './snippetData';
+import { createIndexChunk, writeChunks } from 'build/json';
+import parseMarkdown from './parseMarkdown';
+
+export const compileSnippet = async(
+ snippetsPath, snippet, {
+ sourceDir, commonData, slugPrefix, repoUrlPrefix, assetPath, outPath,
+ langData, language, isCssSnippet, isBlogSnippet, hasOptionalLanguage,
+ languages, icon, biasPenaltyMultiplier, cardTemplate, authors,
+ }
+) => {
+ let data, gitMetadata, tags, text, code, rawCode, type,
+ excerpt, cover, shortSliceIndex, authorsData, langIcon, shortText;
+
+ await Promise.all([
+ getData(snippetsPath, snippet),
+ getGitMetadata(snippet, snippetsPath),
+ ]).then(values => {
+ data = values[0];
+ gitMetadata = values[1];
+ });
+
+ await Promise.all([
+ getTags(data.attributes.tags),
+ getTextualContent(data.body),
+ isBlogSnippet
+ ? [ null, [ ] ]
+ : getCodeBlocks(data.body, {
+ isCssSnippet,
+ hasOptionalLanguage,
+ languages,
+ snippetName: snippet.slice(0, -3),
+ }),
+ isBlogSnippet ? `blog.${data.attributes.type}` : 'snippet',
+ ]).then(values => {
+ tags = values[0];
+ text = values[1];
+ [ code, rawCode ] = values[2];
+ type = values[3];
+ });
+
+ if (isBlogSnippet) {
+ excerpt = data.attributes.excerpt;
+ cover = `${assetPath}${data.attributes.cover}`;
+ shortSliceIndex = text.indexOf('\n\n') <= 180
+ ? text.indexOf('\n\n')
+ : text.indexOf(' ', 160);
+ shortText = excerpt && excerpt.trim().length !== 0
+ ? excerpt
+ : `${text.slice(0, shortSliceIndex)}...`;
+ authorsData = getTags(data.attributes.authors).map(a => authors[a]);
+ langIcon = langData.find(l => tags.includes(l.language));
+ } else
+ shortText = text.slice(0, text.indexOf('\n\n'));
+
+ const html = parseMarkdown(
+ {
+ texts: {
+ fullDescription: isBlogSnippet ? data.body : text,
+ description: shortText,
+ },
+ codeBlocks: rawCode,
+ }, {
+ isBlog: isBlogSnippet,
+ type,
+ assetPath,
+ }
+ );
+
+ const snippetData = {
+ ...commonData,
+ id: getId(snippet, sourceDir),
+ title: data.attributes.title,
+ type,
+ tags: {
+ all: tags,
+ primary: tags[0],
+ },
+ code,
+ expertise: isBlogSnippet ? 'blog' : determineExpertiseFromTags(tags),
+ text: {
+ full: isBlogSnippet ? data.body : text,
+ short: shortText,
+ },
+ cover,
+ authors: authorsData,
+ icon: langIcon ? langIcon.icon : icon,
+ searchTokens: uniqueElements(
+ isBlogSnippet ? [
+ ...stripExpertiseFromTags(tags),
+ ...tokenizeSnippet(`${shortText} ${data.attributes.title}`),
+ ].map(v => v.toLowerCase()) : [
+ data.attributes.title,
+ language.short,
+ language.long,
+ ...stripExpertiseFromTags(tags),
+ ...tokenizeSnippet(shortText),
+ ].map(v => v.toLowerCase())
+ ).join(' '),
+ html,
+ ...gitMetadata,
+ slug: `/${slugPrefix}${convertToSeoSlug(snippet.slice(0, -3))}`,
+ url: `${repoUrlPrefix}/${snippet}`,
+ };
+
+ snippetData.ranking = rankSnippet({
+ ...snippetData,
+ language: commonData.language,
+ biasPenaltyMultiplier: biasPenaltyMultiplier
+ ? biasPenaltyMultiplier
+ : 1.0,
+ });
+
+ await writeChunks(
+ `${outPath}/${snippetData.slug.slice(1)}`,
+ ['index',
+ createIndexChunk(snippetData.slug, 'SnippetPage', (snippetData.ranking * 0.85).toFixed(2)),
+ ],
+ ['snippet', {snippet: transformSnippetContext(snippetData, cardTemplate)}],
+ ['metadata', {
+ cardTemplate,
+ breadcrumbs: transformBreadcrumbs(snippetData, cardTemplate),
+ pageDescription: transformSnippetDescription(snippetData, cardTemplate),
+ }]
+ );
+
+ return {
+ id: snippetData.id,
+ tags: snippetData.tags,
+ language: {
+ long: snippetData.language.long,
+ short: snippetData.language.short,
+ },
+ searchTokens: snippetData.searchTokens,
+ ranking: snippetData.ranking,
+ blog: snippetData.blog,
+ title: snippetData.title,
+ expertise: snippetData.expertise,
+ icon: snippetData.icon,
+ slug: snippetData.slug,
+ html: {
+ description: snippetData.html.description,
+ },
+ };
+};
+
+export default compileSnippet;
diff --git a/src/build/snippet/index.js b/src/build/snippet/index.js
new file mode 100644
index 000000000..db6a88279
--- /dev/null
+++ b/src/build/snippet/index.js
@@ -0,0 +1,25 @@
+import compileSnippet from './compileSnippet';
+import parseMarkdown from './parseMarkdown';
+import readSnippets from './readSnippets';
+import {
+ getFilesInDir,
+ getData,
+ getCodeBlocks,
+ getTextualContent,
+ getGitMetadata,
+ getTags,
+ getId
+} from './snippetData';
+
+export {
+ getFilesInDir,
+ getData,
+ getCodeBlocks,
+ getTextualContent,
+ getGitMetadata,
+ getTags,
+ getId,
+ compileSnippet,
+ parseMarkdown,
+ readSnippets,
+};
diff --git a/src/build/snippet/parseMarkdown.js b/src/build/snippet/parseMarkdown.js
new file mode 100644
index 000000000..0348b33fb
--- /dev/null
+++ b/src/build/snippet/parseMarkdown.js
@@ -0,0 +1,168 @@
+import Remark from 'remark';
+import remarkOptions from 'config/remark';
+import toHAST from 'mdast-util-to-hast';
+import hastToHTML from 'hast-util-to-html';
+import visit from 'unist-util-visit';
+import Prism from 'prismjs';
+import prismComponents from 'prismjs/components';
+import { escapeHTML, optimizeAllNodes } from 'utils';
+
+// Setup Remark using the appropriate options.
+const remark = new Remark().data('settings', remarkOptions);
+
+const transformers = [
+ // Inject class into blog lists' elements
+ {
+ blogType: 'blog.list',
+ matcher: //g,
+ replacer: '',
+ },
+ // Inject paragraphs and class into blog lists' elements
+ {
+ blogType: 'blog.list',
+ matcher: / \n*(.+?)\n((?! ).+?)\n*<\/li>/g,
+ replacer: ' $1
$2',
+ },
+ // Add 'rel' and 'target' to external links
+ {
+ blogType: 'any',
+ matcher: /(href="https?:\/\/)/g,
+ replacer: 'target="_blank" rel="nofollow noopener noreferrer" $1',
+ },
+ // Convert blog post code to the appropriate elements
+ {
+ blogType: 'any',
+ matcher: /
([\s\S]*?)<\/pre>/g,
+ replacer: '$2 ',
+ },
+ // Convert blog blockquotes to the appropriate elements
+ {
+ blogType: 'any',
+ matcher: /\s*\n*\s*([\s\S]*?)<\/p>\s*\n*\s<\/blockquote>/g,
+ replacer: '
$1 ',
+ },
+ // Convert image credit to the appropriate element
+ {
+ blogType: 'any',
+ matcher: /\s*\n*\s*Image credit:<\/strong>([\s\S]*?)<\/p>/g,
+ replacer: 'Image credit: $1
',
+ },
+];
+
+/**
+ * Get the real name of a language given it or an alias.
+ * @param {string} name - Name or alias of a language.
+ */
+const getBaseLanguageName = name => {
+ if (prismComponents.languages[name]) return name;
+ return Object.keys(prismComponents.languages).find(language => {
+ const { alias } = prismComponents.languages[language];
+ if (!alias) return false;
+ return Array.isArray(alias) ? alias.includes(name) : alias === name;
+ });
+};
+
+/**
+ * Loads prism languages on-demand (smartly doesn't load already loaded ones).
+ * Throws and error if the language is invalid or not supported.
+ * @param {string} language - A valid prism language name, as returned from
+ * `getBaseLanguageName` or similar.
+ */
+const loadPrismLanguage = language => {
+ if (!language) throw new Error(`Prism doesn't support language '${language}'.`);
+ const languageData = prismComponents.languages[language];
+ if (Prism.languages[language] || languageData.option === `default`) return;
+
+ if (languageData.require) {
+ // Load the required language first
+ if (Array.isArray(languageData.require))
+ languageData.require.forEach(loadPrismLanguage);
+ else
+ loadPrismLanguage(languageData.require);
+ }
+
+ require(`prismjs/components/prism-${language}.js`);
+};
+
+/**
+ * Given some code and a language, returns the prism-highlighted code.
+ * Automatically gets prim language names and loads languages on demand.
+ * @param {string} language - A language name or alias.
+ * @param {string} code - The code to be highlighted.
+ */
+const highlightCode = (language, code) => {
+ if (!Prism.languages[language]) {
+ const baseLanguage = getBaseLanguageName(language);
+ if(!baseLanguage || baseLanguage === 'text') return escapeHTML(code);
+ loadPrismLanguage(baseLanguage);
+ }
+ return Prism.highlight(code, Prism.languages[language], language);
+};
+
+/**
+ * Parses markdown into HTML from a given markdown string, using remark + prismjs.
+ * @param {string} markdown - The markdown string to be parsed.
+ */
+const parseMarkdown = (markdown, isText = false) => {
+ const ast = remark.parse(markdown);
+
+ // Highlight code blocks
+ visit(ast, `code`, node => {
+ const languageName = node.lang ? node.lang : `text`;
+ node.type = `html`;
+ const highlightedCode = highlightCode(
+ languageName,
+ node.value
+ );
+ node.value = isText
+ ? [
+ ``,
+ `
`,
+ `${highlightedCode.trim()}`,
+ ` `,
+ `
`,
+ ].join('')
+ : `${highlightedCode}`;
+ });
+
+ // Highlight inline code blocks
+ visit(ast, `inlineCode`, node => {
+ node.type = `html`;
+ node.value = `${escapeHTML(node.value)}
`;
+ });
+
+ const htmlAst = toHAST(ast, { allowDangerousHtml: true });
+ return hastToHTML(htmlAst, { allowDangerousHtml: true });
+};
+
+const parseMarkdownSegments = ({texts, codeBlocks}, {isBlog, type, assetPath}) => {
+ const result = {};
+ Object.entries(texts).forEach(([key, value]) => {
+ if(!value) return;
+ result[key] = value.trim() ? parseMarkdown(value, true) : '';
+ });
+ if (isBlog) {
+ result.fullDescription = transformers.reduce(
+ (acc, { blogType, matcher, replacer }) => {
+ if (blogType === 'any' || blogType === type)
+ return acc.replace(matcher, replacer);
+ return acc;
+ },
+ result.fullDescription
+ );
+ // Transform relative paths for images
+ result.fullDescription = result.fullDescription.replace(
+ /()* ]*)>(<\/p>)*/g,
+ (match, openTag, imgSrc, imgRest) =>
+ ` `
+ );
+ } else {
+ Object.entries(codeBlocks).forEach(([key, value]) => {
+ if(!value) return;
+ result[key] = value.trim() ? optimizeAllNodes(parseMarkdown(value)).trim() : '';
+ });
+ }
+ return result;
+};
+
+export default parseMarkdownSegments;
diff --git a/src/build/snippet/readSnippets.js b/src/build/snippet/readSnippets.js
new file mode 100644
index 000000000..e6b6f7eb9
--- /dev/null
+++ b/src/build/snippet/readSnippets.js
@@ -0,0 +1,34 @@
+import { getFilesInDir } from 'build/snippet/snippetData';
+import { compileSnippet } from 'build/snippet/compileSnippet';
+
+/**
+ * Synchronously read all snippets and sort them as necessary.
+ * The sorting is case-insensitive.
+ * @param {string} snippetsPath - The path of the snippets directory.
+ * @param {string} assetPath - The public path of the assets directory.
+ * @param {string} outPath - The output path of the snippets directory.
+ * @param {object} config - The project's enriched configuration
+ * (containing the spread config, commonData and prefixes).
+ * @param {array} langData - An array of `(language, icon)` tuples.
+ * @param {function} boundLog - A bound logger.log function.
+ */
+export const readSnippets = async(snippetsPath, config, boundLog) => {
+ const snippetFilenames = await getFilesInDir(snippetsPath);
+
+ let snippets = [];
+ try {
+ for (let snippet of snippetFilenames) {
+ const snippetData = await compileSnippet(snippetsPath, snippet, config);
+ snippets.push(snippetData);
+ }
+ } catch (err) {
+ /* istanbul ignore next */
+ boundLog(`Fatal error while reading snippets: ${err}`, 'error');
+ boundLog(`Stack trace: ${err.stack}`, 'error');
+ /* istanbul ignore next */
+ process.exit(1);
+ }
+ return snippets;
+};
+
+export default readSnippets;
diff --git a/src/build/snippet/snippetData.js b/src/build/snippet/snippetData.js
new file mode 100644
index 000000000..2f45c8dc0
--- /dev/null
+++ b/src/build/snippet/snippetData.js
@@ -0,0 +1,145 @@
+import fs from 'fs-extra';
+import path from 'path';
+import util from 'util';
+import sass from 'node-sass';
+import frontmatter from 'front-matter';
+import { exec } from 'child_process';
+
+const readFile = util.promisify(fs.readFile);
+const readDir = util.promisify(fs.readdir);
+
+const mdCodeFence = '```';
+const codeMatcher = new RegExp(
+ `${mdCodeFence}[.\\S\\s]*?${mdCodeFence}`,
+ 'g'
+);
+
+/**
+ * Synchronously reads all files in a directory and returns the resulting array.
+ * @param {string} directoryPath - The path of the directory to read.
+ */
+export const getFilesInDir = directoryPath => new Promise((resolve, reject) =>
+ readDir(directoryPath)
+ .then(files => resolve(
+ files.sort((a, b) => a.toLowerCase() < b.toLowerCase() ? -1 : 1)
+ ))
+ .catch(err => reject(err))
+);
+
+/**
+ * Synchronously gets the data from a snippet file in a usable format, using frontmatter.
+ * @param {string} snippetsPath - The path of the snippets directory.
+ * @param {string} snippet - The name of the snippet file.
+ */
+export const getData = (snippetsPath, snippet) => new Promise((resolve, reject) =>
+ readFile(path.join(snippetsPath, snippet), 'utf8')
+ .then(content => resolve(frontmatter(content)))
+ .catch(err => reject(err))
+);
+
+/**
+ * Gets the code blocks for a snippet.
+ * @param {string} str - The snippet's raw content.
+ * @param {object} config - The content repository's configuration file.
+ */
+export const getCodeBlocks = (
+ str,
+ {
+ isCssSnippet = false,
+ hasOptionalLanguage = false,
+ languages = [],
+ snippetName = '',
+ }) => new Promise(resolve => {
+ const replacer = new RegExp(
+ `^${mdCodeFence}(${languages})?`,
+ 'gm'
+ );
+ const raw = Array.from([...str.matchAll(codeMatcher)].map(m => m[0]));
+ const results = raw.map(v => v.replace(replacer, '').trim());
+
+ if(isCssSnippet) {
+ const scopedCss = sass
+ .renderSync({ data: `[data-scope="${snippetName}"] { ${results[1]} }`})
+ .css
+ .toString();
+
+ return resolve([{
+ html: results[0],
+ css: results[1],
+ js: results.length > 2 ? results[2] : '',
+ scopedCss,
+ }, {
+ html: raw[0],
+ css: raw[1],
+ js: raw.length > 2 ? raw[2] : '',
+ }]);
+ }
+
+ if(hasOptionalLanguage && results.length > 2) {
+ return resolve([{
+ style: results[0],
+ src: results[1],
+ example: results[2],
+ }, {
+ style: raw[0],
+ code: raw[1],
+ example: raw[2],
+ }]);
+ }
+
+ return resolve([{
+ style: hasOptionalLanguage ? '' : undefined,
+ src: results[0],
+ example: results[1],
+ }, {
+ style: hasOptionalLanguage ? '' : undefined,
+ code: raw[0],
+ example: raw[1],
+ }]);
+});
+
+/**
+ * Gets the textual content for a snippet.
+ * @param {string} str - The snippet's raw content.
+ */
+export const getTextualContent = str =>
+ str.slice(0, str.indexOf(mdCodeFence)).replace(/\r\n/g, '\n');
+
+/**
+ * Asynchronously gets the git metadata for a snippet.
+ * @param {string} snippet - The name of the snippet file.
+ */
+export const getGitMetadata = (snippet, snippetsPath) => new Promise(resolve => Promise.all([
+ new Promise(rsl => exec(
+ `cd ${snippetsPath}; git log --diff-filter=A --pretty=format:%at -- ${snippet} | head -1`,
+ (error, stdout) => rsl(stdout.toString().replace('\n', ''))
+ )),
+ new Promise(rsl => exec(
+ `cd ${snippetsPath}; git log -n 1 --pretty=format:%at -- ${snippet} | head -1`,
+ (error, stdout) => rsl(stdout.toString().replace('\n', ''))
+ )),
+ new Promise(rsl => exec(
+ `cd ${snippetsPath}; git log --pretty=%H -- ${snippet}`,
+ (error, stdout) => rsl(stdout.toString().split('\n').length)
+ )),
+]).then(values =>
+ resolve({
+ firstSeen: new Date(+`${values[0]}000`),
+ lastUpdated: new Date(+`${values[1]}000`),
+ updateCount: values[2],
+ }))
+);
+
+/**
+ * Gets the tag array for a snippet from the tags string.
+ * @param {string} tagStr - The string of comma-separated tags for the snippet.
+ */
+export const getTags = tagStr => [...new Set(tagStr.toLowerCase().split(','))];
+
+/**
+ * Gets the snippet id from the snippet's filename.
+ * @param {string} snippetFilename - Filename of the snippet.
+ * @param {string} sourceDir - The name of the source directory.
+ */
+export const getId = (snippetFilename, sourceDir) => `${sourceDir}/${snippetFilename.slice(0, -3)}`;
+
From 3ebdeaaa7d5f23fbdc0613f814a702feabb68e77 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 2 Sep 2020 15:53:34 +0300
Subject: [PATCH 26/39] Create build utilities for static content
---
src/build/staticContent/index.js | 8 ++++++++
1 file changed, 8 insertions(+)
create mode 100644 src/build/staticContent/index.js
diff --git a/src/build/staticContent/index.js b/src/build/staticContent/index.js
new file mode 100644
index 000000000..b7175c610
--- /dev/null
+++ b/src/build/staticContent/index.js
@@ -0,0 +1,8 @@
+import { createIndexChunk, writeChunks } from 'build/json';
+
+export const compileStaticData = (outPath, slug, template, priority, context = {}) =>
+ writeChunks(
+ `${outPath}${slug}`,
+ ['index', createIndexChunk(slug, template, priority)],
+ ['context', context]
+ );
From f8ff59e2963fd56a26279ae742d6b128e221c39c Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 2 Sep 2020 16:46:45 +0300
Subject: [PATCH 27/39] Create build utilities for assets
---
src/build/assets/assets.js | 82 ++++++++++++++++++++++++++++
src/build/assets/iconCssTemplate.hbs | 32 +++++++++++
src/build/assets/icons.js | 66 ++++++++++++++++++++++
src/build/assets/index.js | 8 +++
src/config/icons.json | 2 +-
5 files changed, 189 insertions(+), 1 deletion(-)
create mode 100644 src/build/assets/assets.js
create mode 100644 src/build/assets/iconCssTemplate.hbs
create mode 100644 src/build/assets/icons.js
create mode 100644 src/build/assets/index.js
diff --git a/src/build/assets/assets.js b/src/build/assets/assets.js
new file mode 100644
index 000000000..71e983a5a
--- /dev/null
+++ b/src/build/assets/assets.js
@@ -0,0 +1,82 @@
+import fs from 'fs-extra';
+import path from 'path';
+import sharp from 'sharp';
+import glob from 'glob';
+import { bindLogger } from 'build/core';
+
+const supportedExtensions = [
+ 'jpeg', 'jpg', 'png', 'webp', 'tif', 'tiff',
+];
+const maxWidth = 800;
+const outputQuality = 80;
+
+/**
+ *
+ * @param {string} asset - The filename of the given asset.
+ * @param {string} imageDirName - The output directory.
+ */
+export const processImageAsset = (asset, outDir) =>
+ new Promise((resolve, reject) => {
+ const fileName = asset.slice(asset.lastIndexOf('/'));
+ const img = sharp(asset);
+ return img
+ .metadata()
+ .then(metadata => {
+ const resizeWidth = Math.min(maxWidth, metadata.width);
+ const format = metadata.format;
+ return img
+ .resize({ width: resizeWidth })
+ .toFormat(format, { quality: outputQuality })
+ .toFile(
+ `${outDir}/${fileName}`,
+ (err, info) => {
+ if (err) reject(err);
+ else resolve(info);
+ }
+ );
+ });
+ });
+
+/**
+ * Prepares the assets directory.
+ */
+export const prepareAssets = async() => {
+ const boundLog = bindLogger('prepareAssets');
+ const {
+ rawAssetPath: inPath,
+ assetPath: outPath,
+ rawContentPath: contentPath,
+ staticAssetPath: staticAssetPath,
+ } = global.yild.paths;
+ const configs = global.yild.configs;
+ boundLog('Processing assets from config...', 'info');
+
+ boundLog(`Copying static assets from ${path.resolve(inPath)} to ${path.resolve(outPath)}`, 'info');
+ fs.ensureDirSync(outPath);
+ await fs.copy(inPath, outPath);
+ boundLog('Static assets have been copied', 'success');
+
+ boundLog(`Processing image assets from configuration files`, 'info');
+ for (const cfg of configs) {
+ const { images, dirName } = cfg;
+ if (images && images.name && images.path) {
+ fs.ensureDirSync(path.join(outPath, images.name));
+ const assets = glob
+ .sync(`${contentPath}/sources/${dirName}/${images.path}/*.@(${supportedExtensions.join('|')})`)
+ .map(file => path.resolve(file));
+ await Promise.all(assets.map(asset => processImageAsset(asset, `${outPath}/${images.name}`)));
+ }
+ }
+ boundLog(`Processing image assets from configuration files complete`, 'success');
+
+ boundLog(`Copying assets from ${path.resolve(outPath)} to ${path.resolve('static', staticAssetPath)}`, 'info');
+ if(global.yild.env === 'PRODUCTION') {
+ fs.ensureDirSync(path.join('static', staticAssetPath));
+ fs.copySync(outPath, path.join('static', staticAssetPath));
+ }
+ boundLog(`Copying assets complete`, 'success');
+
+ return;
+};
+
+export default prepareAssets;
diff --git a/src/build/assets/iconCssTemplate.hbs b/src/build/assets/iconCssTemplate.hbs
new file mode 100644
index 000000000..08c02a5e9
--- /dev/null
+++ b/src/build/assets/iconCssTemplate.hbs
@@ -0,0 +1,32 @@
+@font-face {
+ font-family: "{{ fontName }}";
+ src: {{{ src }}};
+}
+
+{{ baseSelector }}:before {
+ font-family: {{ fontName }} !important;
+ font-style: normal;
+ font-weight: normal !important;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+{{# each codepoints }}
+{{ ../baseSelector }}.{{ ../classPrefix }}{{ @key }}:before {
+ content: "\\{{ this }}";
+}
+{{/ each }}
+
+{{# each langSelectors }}
+{{this}}{{#if @last}} { {{else}}, {{/if}}
+{{/ each}}
+{{# each langIcons }}
+ &.{{ ../classPrefix }}{{ this.iconName }} {
+ background: {{ this.backColor }};
+ color: {{ this.foreColor }};
+ }
+{{/ each }}
+}
diff --git a/src/build/assets/icons.js b/src/build/assets/icons.js
new file mode 100644
index 000000000..821869850
--- /dev/null
+++ b/src/build/assets/icons.js
@@ -0,0 +1,66 @@
+import glob from 'glob';
+import fs from 'fs-extra';
+import path from 'path';
+import webfontsGenerator from 'webfonts-generator';
+import { bindLogger } from 'build/core';
+
+/**
+ * Generate a woff2 fle with the icon font and CSS styles to go with it.
+ */
+export const makeIcons = () => {
+ const boundLog = bindLogger('makeIcons');
+ const {
+ rawIconPath: inPath,
+ rawAssetPath: outPath,
+ iconFontPath: cssPath,
+ } = global.yild.paths;
+ const configs = global.yild.configs;
+ const {
+ types,
+ fontName,
+ fontRelativePath,
+ cssTemplatePath,
+ cssSelector,
+ cssClassName,
+ cssClassPrefix,
+ cssLanguageSelectors,
+ } = global.yild.icons;
+ const files = glob.sync(`${inPath}`);
+ boundLog(`Generating icon font and styles from ${files.length} files...`, 'info');
+
+ const config = {
+ files,
+ dest: outPath,
+ fontName,
+ types,
+ html: false,
+ css: true,
+ cssDest: cssPath,
+ cssFontsUrl: fontRelativePath,
+ cssTemplate: cssTemplatePath,
+ templateOptions: {
+ baseSelector: cssSelector,
+ baseClassNames: cssClassName,
+ classPrefix: cssClassPrefix,
+ langSelectors: cssLanguageSelectors,
+ langIcons: configs
+ .map(cfg => cfg.theme)
+ .filter(Boolean),
+ },
+ };
+
+ return new Promise((resolve, reject) => {
+ webfontsGenerator(config, (error, result) => {
+ if (error) reject(error);
+ else {
+ const fileName = `${config.dest}/${config.fontName}`;
+ boundLog(`Writing font to ${path.resolve(`${fileName}.${types[0]}`)}...`, 'info');
+ ['svg', 'ttf', 'woff'].forEach(suffix => fs.removeSync(`${fileName}.${suffix}`));
+ boundLog('Generating icon font and styles complete', 'success');
+ resolve(result);
+ }
+ });
+ });
+};
+
+export default makeIcons;
diff --git a/src/build/assets/index.js b/src/build/assets/index.js
new file mode 100644
index 000000000..fd9965e64
--- /dev/null
+++ b/src/build/assets/index.js
@@ -0,0 +1,8 @@
+import { makeIcons } from './icons';
+import { processImageAsset, prepareAssets } from './assets';
+
+export {
+ makeIcons,
+ processImageAsset,
+ prepareAssets
+};
diff --git a/src/config/icons.json b/src/config/icons.json
index d2b66166f..807993264 100644
--- a/src/config/icons.json
+++ b/src/config/icons.json
@@ -2,7 +2,7 @@
"types": ["woff2"],
"fontName": "icons",
"fontRelativePath": "../../assets/",
- "cssTemplatePath": "src/yild/makeIcons/cssTemplate.hbs",
+ "cssTemplatePath": "src/build/assets/iconCssTemplate.hbs",
"cssSelector": ".icon",
"cssClassName": "icon",
"cssClassPrefix": "icon-",
From ba8b54310cd47f6b14448e6a94292b3c5477942d Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 2 Sep 2020 16:47:15 +0300
Subject: [PATCH 28/39] Create yild core (v2)
---
package.json | 2 +-
src/build/config/content.js | 8 +-
.../updateContent => build/content}/index.js | 8 +-
src/build/core/index.js | 9 +
.../index.js => build/core/logger.js} | 11 +-
src/build/extract/index.js | 122 ++++++
src/build/listing/index.js | 2 +-
src/jobs/yild.js | 12 -
src/scripts/build.js | 31 ++
src/yild/core/actions.js | 53 ---
src/yild/core/index.js | 65 ---
src/yild/extractSnippets/extract.js | 61 ---
src/yild/extractSnippets/index.js | 96 -----
src/yild/extractSnippets/parseMarkdown.js | 168 --------
src/yild/extractSnippets/parseSnippets.js | 373 ------------------
src/yild/extractSnippets/postProcess.js | 278 -------------
src/yild/index.js | 56 ---
src/yild/makeIcons/cssTemplate.hbs | 32 --
src/yild/makeIcons/index.js | 68 ----
src/yild/prepareAssets/index.js | 81 ----
src/yild/serveSnippets/index.js | 154 --------
21 files changed, 177 insertions(+), 1513 deletions(-)
rename src/{yild/updateContent => build/content}/index.js (85%)
create mode 100644 src/build/core/index.js
rename src/{yild/logOutput/index.js => build/core/logger.js} (94%)
create mode 100644 src/build/extract/index.js
delete mode 100644 src/jobs/yild.js
create mode 100644 src/scripts/build.js
delete mode 100644 src/yild/core/actions.js
delete mode 100644 src/yild/core/index.js
delete mode 100644 src/yild/extractSnippets/extract.js
delete mode 100644 src/yild/extractSnippets/index.js
delete mode 100644 src/yild/extractSnippets/parseMarkdown.js
delete mode 100644 src/yild/extractSnippets/parseSnippets.js
delete mode 100644 src/yild/extractSnippets/postProcess.js
delete mode 100644 src/yild/index.js
delete mode 100644 src/yild/makeIcons/cssTemplate.hbs
delete mode 100644 src/yild/makeIcons/index.js
delete mode 100644 src/yild/prepareAssets/index.js
delete mode 100644 src/yild/serveSnippets/index.js
diff --git a/package.json b/package.json
index 78a1854e4..5b8fe3f3f 100644
--- a/package.json
+++ b/package.json
@@ -74,7 +74,7 @@
"watch-assets": "npm-watch prepare-assets",
"serve-snippets": "NODE_PATH=src NODE_ENV=development npx --node-arg '-r esm' ./src/jobs/yild.js -s",
"yild": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js",
- "prebuild": "NODE_PATH=src NODE_ENV=production npx --node-arg '-r esm' ./src/jobs/yild.js -u -a -e -i",
+ "prebuild": "NODE_PATH=src NODE_ENV=production npx --node-arg '-r esm' ./src/scripts/build.js",
"predevelop": "NODE_PATH=src NODE_ENV=development npx --node-arg '-r esm' ./src/jobs/yild.js",
"pretest": "NODE_PATH=src NODE_ENV=test npx --node-arg '-r esm' ./src/jobs/yild.js",
"build": "NODE_PATH=src npx --node-arg '-r esm' gatsby build",
diff --git a/src/build/config/content.js b/src/build/config/content.js
index aeb8f19af..5596004ee 100644
--- a/src/build/config/content.js
+++ b/src/build/config/content.js
@@ -13,7 +13,7 @@ export const getRichConfigs = (configs, langData) => configs.map(cfg => {
const {
contentPath: contentOutDir,
staticAssetPath: assetDir,
- } = global._yild_instance.config.paths;
+ } = global.yild.paths;
const assetPath = `/${assetDir}/`;
cfg.assetPath = assetPath;
@@ -60,8 +60,8 @@ export const getRichConfigs = (configs, langData) => configs.map(cfg => {
export const loadContentConfigs = (inPath, boundLog) => {
boundLog(`Loading individual configuration files in ${path.resolve(inPath, 'configs')}`, 'info');
let configs = [];
- if(global._yild_instance.contentConfigs) {
- configs = global._yild_instance.contentConfigs;
+ if(global.yild.configs) {
+ configs = global.yild.configs;
boundLog(`Using already loaded configuration files`, 'success');
} else {
const rawConfigs = glob.sync(`${inPath}/configs/*.json`)
@@ -78,7 +78,7 @@ export const loadContentConfigs = (inPath, boundLog) => {
boundLog(`Processed data for ${langData.length} languages`, 'success');
configs = getRichConfigs(rawConfigs, langData);
- global._yild_instance.contentConfigs = configs;
+ global.yild.configs = configs;
boundLog(`Loaded ${configs.length} configuration files`, 'success');
}
return configs;
diff --git a/src/yild/updateContent/index.js b/src/build/content/index.js
similarity index 85%
rename from src/yild/updateContent/index.js
rename to src/build/content/index.js
index b5d74764d..34295b708 100644
--- a/src/yild/updateContent/index.js
+++ b/src/build/content/index.js
@@ -1,12 +1,12 @@
import childProcess from 'child_process';
-import { initAction } from '../core';
+import { bindLogger } from 'build/core';
/**
* Update content sources from their respective GitHub repositories.
* Returns a promise that resolves as soon as the spawned git command exits.
*/
-const updateContent = () => {
- const [boundLog] = initAction('updateContent');
+export const updateContent = () => {
+ const boundLog = bindLogger('updateContent');
boundLog('Updating content sources started...', 'info');
return new Promise((resolve, reject) => {
@@ -26,5 +26,3 @@ const updateContent = () => {
});
});
};
-
-export default updateContent;
diff --git a/src/build/core/index.js b/src/build/core/index.js
new file mode 100644
index 000000000..a0db39971
--- /dev/null
+++ b/src/build/core/index.js
@@ -0,0 +1,9 @@
+import logger, { format } from './logger';
+
+const bindLogger = name => logger.bindProcessLogger(name);
+
+export {
+ logger,
+ format,
+ bindLogger
+};
diff --git a/src/yild/logOutput/index.js b/src/build/core/logger.js
similarity index 94%
rename from src/yild/logOutput/index.js
rename to src/build/core/logger.js
index f1cbf021b..8271aff2b 100644
--- a/src/yild/logOutput/index.js
+++ b/src/build/core/logger.js
@@ -2,7 +2,8 @@ import chalk from 'chalk';
import process from 'process';
const { bold, blue, green, red, yellow } = chalk;
-global._yild_logOutput_instance = undefined;
+global.yild = global.yild || {};
+global.yild.logger = undefined;
/**
* Format a string with the given chalk formatter.
@@ -18,8 +19,8 @@ export const format = (msg, ...format) =>
*/
function logger() {
// Return singleton if exists, instantiate otherwise.
- if (global._yild_logOutput_instance) return global._yild_logOutput_instance;
- global._yild_logOutput_instance = this;
+ if (global.yild.logger) return global.yild.logger;
+ global.yild.logger = this;
this.outputStream = process.stdout;
const prefixes = {
@@ -136,10 +137,10 @@ function logger() {
information.forEach(i => this.log(i));
};
- return global._yild_logOutput_instance;
+ return global.yild.logger;
}
// IIFE here to instantiate the logger
(() => new logger())();
-export default global._yild_logOutput_instance;
+export default global.yild.logger;
diff --git a/src/build/extract/index.js b/src/build/extract/index.js
new file mode 100644
index 000000000..9fc9a1aa2
--- /dev/null
+++ b/src/build/extract/index.js
@@ -0,0 +1,122 @@
+import fs from 'fs-extra';
+import { bindLogger } from 'build/core';
+import { transformSnippetIndex } from 'build/transformers';
+import { writeChunks } from 'build/json';
+import { readSnippets } from 'build/snippet';
+import { compileListingData } from 'build/listing';
+import { compileStaticData } from 'build/staticContent';
+import recommendationEngine from 'engines/recommendationEngine';
+import { uniqueElements } from 'utils';
+import literals from 'lang/en';
+
+const extract = (configs, boundLog) => configs.map(cfg => {
+ const {
+ rawContentPath: contentDir,
+ } = global.yild.paths;
+ const snippetsPath = `${contentDir}/sources/${cfg.dirName}/${cfg.snippetPath}`;
+ boundLog(`Extracting snippets from ${snippetsPath}`, 'info');
+
+ return new Promise((resolve, reject) =>
+ readSnippets(snippetsPath, cfg, boundLog)
+ .then(snippetsArray => {
+ const completeData = {
+ data: snippetsArray,
+ meta: {
+ name: cfg.isBlog ? literals.listing.blog : literals.listing.codelang(cfg.language.long),
+ tags: uniqueElements(
+ snippetsArray.map(snippet => snippet.tags.primary)
+ ).sort((a, b) => a.localeCompare(b)),
+ url: `/${cfg.slugPrefix.slice(0, cfg.slugPrefix.indexOf('/'))}/p/1`,
+ slugPrefix: `/${cfg.slug}`,
+ featured: cfg.featured ? cfg.featured : 0,
+ blog: cfg.isBlog,
+ icon: cfg.theme && cfg.theme.iconName,
+ },
+ };
+ boundLog(`Finished extracting ${snippetsPath}`, 'success');
+ resolve({
+ snippetsPath,
+ data: completeData,
+ });
+ })
+ .catch(err => {
+ boundLog(`Encountered an error while extracting ${snippetsPath}`, 'error');
+ boundLog(`${err}`, 'error');
+ reject(err);
+ })
+ );
+});
+
+const postProcess = (allData, allSnippetData, boundLog) => {
+ // Generate listing data and write snippet recommendations
+ return [
+ compileListingData(allSnippetData, allData.map(({ data }) => data.meta)),
+ ...allData.map(async({ snippetsPath, data }) => {
+ const {
+ contentPath: contentOutDir,
+ } = global.yild.paths;
+ boundLog(`Post-processing snippets for ${snippetsPath}`, 'info');
+
+ for (let snippet of data.data) {
+ await writeChunks(
+ `${contentOutDir}/${snippet.slug.slice(1)}`,
+ ['recommendations', {
+ recommendedSnippets: transformSnippetIndex(
+ recommendationEngine(allSnippetData, snippet)
+ ),
+ }]
+ );
+ }
+ }),
+ ];
+};
+
+export const extractData = async() => {
+ const boundLog = bindLogger('extractData');
+ const {
+ contentPath: outPath,
+ } = global.yild.paths;
+ const configs = global.yild.configs;
+ fs.ensureDirSync(outPath);
+ let allData = [];
+
+ boundLog('Extracting snippet data', 'info');
+ await Promise
+ .all(extract(configs, boundLog))
+ .then(res => { allData = res; });
+ const allSnippetData = allData
+ .reduce((acc, r) => [...acc, ...r.data.data], [])
+ .sort((a, b) => b.ranking - a.ranking);
+ boundLog(`Extracted data for ${allSnippetData.length} snippets`, 'success');
+
+ boundLog('Post-processing snippet data', 'info');
+ await Promise
+ .all(postProcess(allData, allSnippetData, boundLog));
+ boundLog('Snippet post-processing complete', 'success');
+
+ boundLog('Creating static data files', 'info');
+ await Promise.all([
+ compileStaticData(outPath, '/404', 'NotFoundPage', 0),
+ compileStaticData(outPath, '/about', 'StaticPage', 0.25,
+ { stringLiterals: literals.about }
+ ),
+ compileStaticData(outPath, '/cookies', 'StaticPage', 0.25,
+ { stringLiterals: literals.cookies }
+ ),
+ compileStaticData(outPath, '/settings', 'SettingsPage', 0.05,
+ { stringLiterals: literals.settings }
+ ),
+ compileStaticData(outPath, '/search', 'SearchPage', 0.25,
+ {
+ searchIndex: transformSnippetIndex(allSnippetData, true),
+ recommendedSnippets: transformSnippetIndex(allSnippetData.slice(0, 3)),
+ pageDescription: literals.search.pageDescription(allSnippetData.length),
+ }
+ ),
+ ]);
+ boundLog('Static data creation complete', 'info');
+
+ return;
+};
+
+export default extractData;
diff --git a/src/build/listing/index.js b/src/build/listing/index.js
index ad9bd2093..7349e28c8 100644
--- a/src/build/listing/index.js
+++ b/src/build/listing/index.js
@@ -21,7 +21,7 @@ export const compileListingPages = async(
) => {
const {
contentPath: contentOutDir,
- } = global._yild_instance.config.paths;
+ } = global.yild.paths;
for (let [i, chunk] of chunks.entries()) {
const isPopularityOrdered = slugOrderingSegment === 'p';
diff --git a/src/jobs/yild.js b/src/jobs/yild.js
deleted file mode 100644
index 6c61a1bf0..000000000
--- a/src/jobs/yild.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/* eslint-disable no-new */
-const paths = require('config/paths');
-import yild from 'yild';
-const processArgs = process.argv.slice(2);
-
-/**
- * Run yild with the supplied combined configuration.
- */
-yild({
- args: processArgs,
- paths,
-});
diff --git a/src/scripts/build.js b/src/scripts/build.js
new file mode 100644
index 000000000..9d042d05c
--- /dev/null
+++ b/src/scripts/build.js
@@ -0,0 +1,31 @@
+import { logger, format } from 'build/core';
+import { loadContentConfigs } from 'build/config';
+import { updateContent } from 'build/content';
+import { makeIcons, prepareAssets } from 'build/assets';
+import { extractData } from 'build/extract';
+import pathConfig from 'config/paths';
+import iconConfig from 'config/icons';
+
+export const build = async() => {
+ global.yild = global.yild || {};
+ global.yild.paths = pathConfig;
+ global.yild.icons = iconConfig;
+ global.yild.env = 'PRODUCTION';
+
+ logger.log(`${format('yild', 'bold')} is starting up...`, 'info');
+ logger.logProcessInfo();
+ logger.breakLine();
+ loadContentConfigs(pathConfig.rawContentPath, logger.log);
+
+ await Promise.all([
+ updateContent(),
+ makeIcons(),
+ ]);
+
+ await Promise.all([
+ extractData(),
+ prepareAssets(),
+ ]);
+};
+
+build();
diff --git a/src/yild/core/actions.js b/src/yild/core/actions.js
deleted file mode 100644
index 3d10e3e1c..000000000
--- a/src/yild/core/actions.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import prepareAssets from '../prepareAssets';
-import extractSnippets from '../extractSnippets';
-import serveSnippets from '../serveSnippets';
-import updateContent from '../updateContent';
-import makeIcons from '../makeIcons';
-
-// Keep this in a variable to allow for help to run the way it should.
-export const helpFlag = /^-{0,2}h(elp)?$/gi;
-
-/**
- * Actions object for yild.
- */
-const actions = {
- // Do not remove to show up in the "man" page of the tool.
- 'help': {
- description: 'display this text and exit',
- process: () => {},
- step: -1,
- matcher: helpFlag,
- },
- 'assets': {
- description: 'preprocess assets from the provided config paths',
- process: prepareAssets,
- step: 1,
- matcher: /^-{0,2}a(ssets)?$/gi,
- },
- 'extract': {
- description: 'extract snippets from the provided config paths',
- process: extractSnippets,
- step: 1,
- matcher: /^-{0,2}e(xtract)?$/gi,
- },
- 'update': {
- description: 'fetch content sources from the respective repos',
- process: updateContent,
- step: 0,
- matcher: /^-{0,2}u(pdate)?$/gi,
- },
- 'icons': {
- description: 'generate an icon font from the provided SVGs',
- process: makeIcons,
- step: 0,
- matcher: /^-{0,2}i(cons)?$/gi,
- },
- 'serve': {
- description: 'serve snippets from the generated JSON files',
- process: serveSnippets,
- step: 2,
- matcher: /^-{0,2}s(erve)?$/gi,
- },
-};
-
-export default actions;
diff --git a/src/yild/core/index.js b/src/yild/core/index.js
deleted file mode 100644
index 1dd93c050..000000000
--- a/src/yild/core/index.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import path from 'path';
-import glob from 'glob';
-import logger from '../logOutput';
-import { hasKeys, get } from 'utils';
-
-/**
- * Initializes a yild action.
- * @param {string} actionName - The name of the action.
- * @param {array} requiredKeys - A 2D array of required keys.
- * @returns {array} - An array of the form [boundLog, config, requiredKeyValues]
- */
-export const initAction = (actionName, requiredKeys = []) => {
- const boundLog = logger.bindProcessLogger(actionName);
- if (typeof global._yild_instance === 'undefined' ||
- typeof global._yild_instance.config === 'undefined') {
- logger.log(
- 'Fatal error: yild instance or config not found. Exiting...',
- 'error'
- );
- return process.exit(1);
- }
-
- const config = global._yild_instance.config;
- if (requiredKeys.length && !hasKeys(config, requiredKeys)) {
- logger.log(
- 'Fatal error: one or more keys in the following list are not present:',
- 'error'
- );
- logger.log(
- requiredKeys.map(k => Array.isArray(k) ? k.join('.') : k).join(', '),
- 'error'
- );
- return process.exit(1);
- }
-
- return [boundLog, config, ...get(config, requiredKeys)];
-};
-
-/**
- * Loads the content configuration files. Will use stored ones, if they exist.
- * @param {string} inPath - Name of the directory where the configs are located.
- * @param {logger} boundLog - A bound logger.log function.
- * @returns {array} - An array of content configs;
- */
-export const loadContentConfigs = (inPath, boundLog) => {
- boundLog(`Loading individual configuration files in ${path.resolve(inPath, 'configs')}`, 'info');
- let configs = [];
- if(global._yild_instance.contentConfigs) {
- configs = global._yild_instance.contentConfigs;
- boundLog(`Using already loaded configuration files`, 'success');
- } else {
- glob.sync(`${inPath}/configs/*.json`)
- .forEach( file => {
- configs.push(
- require( path.resolve( file ) )
- );
- });
- global._yild_instance.contentConfigs = configs;
- boundLog(`Loaded ${configs.length} configuration files`, 'success');
- }
- return configs;
-};
-
-export { helpFlag } from './actions';
-export { default as actions } from './actions';
diff --git a/src/yild/extractSnippets/extract.js b/src/yild/extractSnippets/extract.js
deleted file mode 100644
index 291bdb245..000000000
--- a/src/yild/extractSnippets/extract.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import parseSnippets from './parseSnippets';
-import { uniqueElements } from 'utils';
-import literals from 'lang/en/listing';
-
-const extract = (configs, langData, parentLog) => configs.map(cfg => {
- const {
- rawContentPath: contentDir,
- contentPath: contentOutDir,
- staticAssetPath: assetDir,
- } = global._yild_instance.config.paths;
- const boundLog = parentLog.rebind('extract');
-
- const snippetsPath = `${contentDir}/sources/${cfg.dirName}/${cfg.snippetPath}`;
- const assetPath = `/${assetDir}/`;
- const slugPrefix = `${cfg.slug}/s`;
- const repoUrlPrefix = `${cfg.repoUrl}/blob/master/${cfg.snippetPath}`;
- const isBlog = !!cfg.isBlog;
- const commonData = {
- blog: isBlog,
- language: cfg.language || {},
- };
- let otherLanguages = [];
- if (cfg.secondLanguage) otherLanguages.push(cfg.secondLanguage);
- if (cfg.optionalLanguage) otherLanguages.push(cfg.optionalLanguage);
- if (otherLanguages.length) commonData.language.otherLanguages = otherLanguages;
- if (!cfg.cardTemplate) cfg.cardTemplate = 'StandardSnippetCard';
-
- boundLog(`Extracting snippets from ${snippetsPath}`, 'info');
- return new Promise((resolve, reject) =>
- parseSnippets(snippetsPath, assetPath, contentOutDir, {...cfg, commonData, slugPrefix, repoUrlPrefix}, langData, boundLog)
- .then(snippetsArray => {
- const completeData = {
- data: snippetsArray,
- meta: {
- name: isBlog ? literals.blog : literals.codelang(cfg.language.long),
- count: literals.snippetCount(snippetsArray.length),
- tags: uniqueElements(
- snippetsArray.map(snippet => snippet.tags.primary)
- ).sort((a, b) => a.localeCompare(b)),
- url: `/${slugPrefix.slice(0, slugPrefix.indexOf('/'))}/p/1`,
- slugPrefix: `/${cfg.slug}`,
- featured: cfg.featured ? cfg.featured : 0,
- blog: isBlog,
- icon: cfg.theme && cfg.theme.iconName,
- },
- };
- boundLog(`Finished extracting ${snippetsPath}`, 'success');
- resolve({
- snippetsPath,
- data: completeData,
- });
- })
- .catch(err => {
- boundLog(`Encountered an error while extracting ${snippetsPath}`, 'error');
- boundLog(`${err}`, 'error');
- reject(err);
- })
- );
-});
-
-export default extract;
diff --git a/src/yild/extractSnippets/index.js b/src/yild/extractSnippets/index.js
deleted file mode 100644
index d6b885f65..000000000
--- a/src/yild/extractSnippets/index.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import fs from 'fs-extra';
-import { initAction, loadContentConfigs } from '../core';
-import extract from './extract';
-import postProcess from './postProcess';
-import literals from 'lang/en';
-import { transformSnippetIndex } from 'build/transformers';
-
-const extractSnippets = async() => {
- const [boundLog, , inPath, outPath] = initAction('extractSnippets', [
- ['paths', 'rawContentPath'], ['paths', 'contentPath'],
- ]);
-
- boundLog('Extracting snippets from config...', 'info');
- const configs = loadContentConfigs(inPath, boundLog);
- const langData = configs
- .filter(cfg =>
- cfg.language && cfg.language.long &&
- cfg.theme && cfg.theme.iconName
- )
- .map(cfg => ({
- language: cfg.language.long.toLowerCase(),
- icon: cfg.theme.iconName,
- }));
- boundLog(`Processed data for ${langData.length} languages`, 'success');
-
- boundLog('Extracting snippet data', 'info');
- fs.ensureDirSync(outPath);
- let allData = [];
- await Promise
- .all(extract(configs, langData, boundLog))
- .then(res => { allData = res; });
- const allSnippetData = allData
- .reduce((acc, r) => [...acc, ...r.data.data], [])
- .sort((a, b) => b.ranking - a.ranking);
- boundLog(`Extracted data for ${allSnippetData.length} snippets`, 'success');
-
- boundLog('Post-processing snippet data', 'info');
- await Promise
- .all(postProcess(allData, allSnippetData, boundLog));
- boundLog('Snippet post-processing complete', 'success');
-
- // TODO: Temporary, let's move this after the next restructure
- [
- {
- slug: '/404',
- context: {},
- template: 'NotFoundPage',
- priority: 0.0,
- },
- {
- slug: '/about',
- context: {stringLiterals: literals.about},
- template: 'StaticPage',
- priority: 0.25,
- },
- {
- slug: '/cookies',
- context: {stringLiterals: literals.cookies},
- template: 'StaticPage',
- priority: 0.25,
- },
- {
- slug: '/settings',
- context: {stringLiterals: literals.settings},
- template: 'SettingsPage',
- priority: 0.01,
- },
- {
- slug: '/search',
- context: {
- searchIndex: transformSnippetIndex(allSnippetData, true),
- recommendedSnippets: transformSnippetIndex(allSnippetData.slice(0, 3)),
- pageDescription: literals.search.pageDescription(allSnippetData.length),
- },
- template: 'SearchPage',
- priority: 0.25,
- },
- ].forEach(p => {
- const outDir = `${outPath}${p.slug}`;
- fs.ensureDirSync(outDir);
- fs.writeFileSync(
- `${outDir}/index.json`,
- JSON.stringify({
- template: p.template,
- fullRoute: `https://30secondsofcode.org${p.slug}`,
- relRoute: p.slug,
- priority: p.priority,
- }, null, 2)
- );
- fs.writeFileSync(`${outDir}/context.json`, JSON.stringify(p.context, null, 2));
- });
-
- return;
-};
-
-export default extractSnippets;
diff --git a/src/yild/extractSnippets/parseMarkdown.js b/src/yild/extractSnippets/parseMarkdown.js
deleted file mode 100644
index 0348b33fb..000000000
--- a/src/yild/extractSnippets/parseMarkdown.js
+++ /dev/null
@@ -1,168 +0,0 @@
-import Remark from 'remark';
-import remarkOptions from 'config/remark';
-import toHAST from 'mdast-util-to-hast';
-import hastToHTML from 'hast-util-to-html';
-import visit from 'unist-util-visit';
-import Prism from 'prismjs';
-import prismComponents from 'prismjs/components';
-import { escapeHTML, optimizeAllNodes } from 'utils';
-
-// Setup Remark using the appropriate options.
-const remark = new Remark().data('settings', remarkOptions);
-
-const transformers = [
- // Inject class into blog lists' elements
- {
- blogType: 'blog.list',
- matcher: //g,
- replacer: '',
- },
- // Inject paragraphs and class into blog lists' elements
- {
- blogType: 'blog.list',
- matcher: / \n*(.+?)\n((?! ).+?)\n*<\/li>/g,
- replacer: ' $1
$2',
- },
- // Add 'rel' and 'target' to external links
- {
- blogType: 'any',
- matcher: /(href="https?:\/\/)/g,
- replacer: 'target="_blank" rel="nofollow noopener noreferrer" $1',
- },
- // Convert blog post code to the appropriate elements
- {
- blogType: 'any',
- matcher: /
([\s\S]*?)<\/pre>/g,
- replacer: '$2 ',
- },
- // Convert blog blockquotes to the appropriate elements
- {
- blogType: 'any',
- matcher: /\s*\n*\s*([\s\S]*?)<\/p>\s*\n*\s<\/blockquote>/g,
- replacer: '
$1 ',
- },
- // Convert image credit to the appropriate element
- {
- blogType: 'any',
- matcher: /\s*\n*\s*Image credit:<\/strong>([\s\S]*?)<\/p>/g,
- replacer: 'Image credit: $1
',
- },
-];
-
-/**
- * Get the real name of a language given it or an alias.
- * @param {string} name - Name or alias of a language.
- */
-const getBaseLanguageName = name => {
- if (prismComponents.languages[name]) return name;
- return Object.keys(prismComponents.languages).find(language => {
- const { alias } = prismComponents.languages[language];
- if (!alias) return false;
- return Array.isArray(alias) ? alias.includes(name) : alias === name;
- });
-};
-
-/**
- * Loads prism languages on-demand (smartly doesn't load already loaded ones).
- * Throws and error if the language is invalid or not supported.
- * @param {string} language - A valid prism language name, as returned from
- * `getBaseLanguageName` or similar.
- */
-const loadPrismLanguage = language => {
- if (!language) throw new Error(`Prism doesn't support language '${language}'.`);
- const languageData = prismComponents.languages[language];
- if (Prism.languages[language] || languageData.option === `default`) return;
-
- if (languageData.require) {
- // Load the required language first
- if (Array.isArray(languageData.require))
- languageData.require.forEach(loadPrismLanguage);
- else
- loadPrismLanguage(languageData.require);
- }
-
- require(`prismjs/components/prism-${language}.js`);
-};
-
-/**
- * Given some code and a language, returns the prism-highlighted code.
- * Automatically gets prim language names and loads languages on demand.
- * @param {string} language - A language name or alias.
- * @param {string} code - The code to be highlighted.
- */
-const highlightCode = (language, code) => {
- if (!Prism.languages[language]) {
- const baseLanguage = getBaseLanguageName(language);
- if(!baseLanguage || baseLanguage === 'text') return escapeHTML(code);
- loadPrismLanguage(baseLanguage);
- }
- return Prism.highlight(code, Prism.languages[language], language);
-};
-
-/**
- * Parses markdown into HTML from a given markdown string, using remark + prismjs.
- * @param {string} markdown - The markdown string to be parsed.
- */
-const parseMarkdown = (markdown, isText = false) => {
- const ast = remark.parse(markdown);
-
- // Highlight code blocks
- visit(ast, `code`, node => {
- const languageName = node.lang ? node.lang : `text`;
- node.type = `html`;
- const highlightedCode = highlightCode(
- languageName,
- node.value
- );
- node.value = isText
- ? [
- ``,
- `
`,
- `${highlightedCode.trim()}`,
- ` `,
- `
`,
- ].join('')
- : `${highlightedCode}`;
- });
-
- // Highlight inline code blocks
- visit(ast, `inlineCode`, node => {
- node.type = `html`;
- node.value = `${escapeHTML(node.value)}
`;
- });
-
- const htmlAst = toHAST(ast, { allowDangerousHtml: true });
- return hastToHTML(htmlAst, { allowDangerousHtml: true });
-};
-
-const parseMarkdownSegments = ({texts, codeBlocks}, {isBlog, type, assetPath}) => {
- const result = {};
- Object.entries(texts).forEach(([key, value]) => {
- if(!value) return;
- result[key] = value.trim() ? parseMarkdown(value, true) : '';
- });
- if (isBlog) {
- result.fullDescription = transformers.reduce(
- (acc, { blogType, matcher, replacer }) => {
- if (blogType === 'any' || blogType === type)
- return acc.replace(matcher, replacer);
- return acc;
- },
- result.fullDescription
- );
- // Transform relative paths for images
- result.fullDescription = result.fullDescription.replace(
- /()* ]*)>(<\/p>)*/g,
- (match, openTag, imgSrc, imgRest) =>
- ` `
- );
- } else {
- Object.entries(codeBlocks).forEach(([key, value]) => {
- if(!value) return;
- result[key] = value.trim() ? optimizeAllNodes(parseMarkdown(value)).trim() : '';
- });
- }
- return result;
-};
-
-export default parseMarkdownSegments;
diff --git a/src/yild/extractSnippets/parseSnippets.js b/src/yild/extractSnippets/parseSnippets.js
deleted file mode 100644
index 97167b679..000000000
--- a/src/yild/extractSnippets/parseSnippets.js
+++ /dev/null
@@ -1,373 +0,0 @@
-import fs from 'fs-extra';
-import path from 'path';
-import sass from 'node-sass';
-import frontmatter from 'front-matter';
-import { exec } from 'child_process';
-import tokenizeSnippet from 'engines/searchIndexingEngine';
-import { convertToSeoSlug, uniqueElements } from 'utils';
-import {
- determineExpertiseFromTags,
- stripExpertiseFromTags,
- transformSnippetContext,
- transformBreadcrumbs,
- transformSnippetDescription
-} from 'build/transformers';
-import rankSnippet from 'engines/rankingEngine';
-import parseMarkdown from './parseMarkdown';
-// TODO: Consider parsing this via a new parser or similar
-// The argument against is that it's a single case and might not extend to other repos in the future
-import authors from '../../../content/sources/30blog/blog_data/blog_authors';
-
-const mdCodeFence = '```';
-const codeMatcher = new RegExp(
- `${mdCodeFence}[.\\S\\s]*?${mdCodeFence}`,
- 'g'
-);
-
-/**
- * Synchronously reads all files in a directory and returns the resulting array.
- * @param {string} directoryPath - The path of the directory to read.
- * @param {function} boundLog - A bound logger.log function.
- */
-export const getFilesInDir = (directoryPath, boundLog) => {
- try {
- return fs.readdirSync(directoryPath)
- .sort((a, b) => a.toLowerCase() < b.toLowerCase() ? -1 : 1);
- } catch (err) {
- /* istanbul ignore next */
- boundLog(`Fatal error while getting directory files: ${err}', 'error`);
- boundLog(`Stack trace: ${err.stack}`, 'error');
- /* istanbul ignore next */
- process.exit(1);
- }
-};
-
-/**
- * Synchronously gets the data from a snippet file in a usable format, using frontmatter.
- * @param {string} snippetsPath - The path of the snippets directory.
- * @param {string} snippet - The name of the snippet file.
- */
-export const getData = (snippetsPath, snippet) => new Promise((resolve, reject) => {
- fs.readFile(path.join(snippetsPath, snippet), 'utf8', (err, content) => {
- if(err) reject(err);
- resolve(frontmatter(content));
- });
-});
-
-/**
- * Gets the code blocks for a snippet.
- * @param {string} str - The snippet's raw content.
- * @param {object} config - The content repository's configuration file.
- */
-export const getCodeBlocks = (
- str,
- {
- isCssSnippet = false,
- hasOptionalLanguage = false,
- languages = [],
- snippetName = '',
- }) => {
- const replacer = new RegExp(
- `^${mdCodeFence}(${languages})?`,
- 'gm'
- );
- const raw = Array.from([...str.matchAll(codeMatcher)].map(m => m[0]));
- const results = raw.map(v => v.replace(replacer, '').trim());
-
- if(isCssSnippet) {
- const scopedCss = sass
- .renderSync({ data: `[data-scope="${snippetName}"] { ${results[1]} }`})
- .css
- .toString();
-
- return [{
- html: results[0],
- css: results[1],
- js: results.length > 2 ? results[2] : '',
- scopedCss,
- }, {
- html: raw[0],
- css: raw[1],
- js: raw.length > 2 ? raw[2] : '',
- }];
- }
-
- if(hasOptionalLanguage && results.length > 2) {
- return [{
- style: results[0],
- src: results[1],
- example: results[2],
- }, {
- style: raw[0],
- code: raw[1],
- example: raw[2],
- }];
- }
-
- return [{
- style: hasOptionalLanguage ? '' : undefined,
- src: results[0],
- example: results[1],
- }, {
- style: hasOptionalLanguage ? '' : undefined,
- code: raw[0],
- example: raw[1],
- }];
-};
-
-/**
- * Gets the textual content for a snippet.
- * @param {string} str - The snippet's raw content.
- */
-export const getTextualContent = str =>
- str.slice(0, str.indexOf(mdCodeFence)).replace(/\r\n/g, '\n');
-
-/**
- * Asynchronously gets the git metadata for a snippet.
- * @param {string} snippet - The name of the snippet file.
- */
-export const getGitMetadata = async(snippet, snippetsPath) => {
- const getFirstSeen = new Promise(resolve => exec(
- `cd ${snippetsPath}; git log --diff-filter=A --pretty=format:%at -- ${snippet} | head -1`,
- (error, stdout) => resolve(stdout.toString().replace('\n', ''))
- ));
- const getLastUpdated = new Promise(resolve => exec(
- `cd ${snippetsPath}; git log -n 1 --pretty=format:%at -- ${snippet} | head -1`,
- (error, stdout) => resolve(stdout.toString().replace('\n', ''))
- ));
- const getUpdateCount = new Promise(resolve => exec(
- `cd ${snippetsPath}; git log --pretty=%H -- ${snippet}`,
- (error, stdout) => resolve(stdout.toString().split('\n').length)
- ));
- let metaData = {};
- await Promise.all([
- getFirstSeen,
- getLastUpdated,
- getUpdateCount,
- ]).then(values => {
- metaData = {
- firstSeen: new Date(+`${values[0]}000`),
- lastUpdated: new Date(+`${values[1]}000`),
- updateCount: values[2],
- };
- });
- return metaData;
-};
-
-/**
- * Gets the tag array for a snippet from the tags string.
- * @param {string} tagStr - The string of comma-separated tags for the snippet.
- */
-export const getTags = tagStr => [...new Set(tagStr.split(','))];
-
-/**
- * Gets the snippet id from the snippet's filename.
- * @param {string} snippetFilename - Filename of the snippet.
- * @param {string} sourceDir - The name of the source directory.
- */
-export const getId = (snippetFilename, sourceDir) => `${sourceDir}/${snippetFilename.slice(0, -3)}`;
-
-export const parseSnippet = async(
- snippetsPath, snippet, {
- sourceDir, commonData, slugPrefix, repoUrlPrefix, assetPath, outPath,
- langData, language, isCssSnippet, isBlogSnippet, hasOptionalLanguage,
- languages, icon, biasPenaltyMultiplier, cardTemplate,
- }
-) => {
- let data, gitMetadata;
- await Promise.all([
- getData(snippetsPath, snippet),
- getGitMetadata(snippet, snippetsPath),
- ]).then(values => {
- data = values[0];
- gitMetadata = values[1];
- });
- const tags = getTags(data.attributes.tags);
- const text = getTextualContent(data.body);
- const [ code, rawCode ] = isBlogSnippet
- ? [ null, [ ] ]
- : getCodeBlocks(data.body, {
- isCssSnippet,
- hasOptionalLanguage,
- languages,
- snippetName: snippet.slice(0, -3),
- });
- const type = isBlogSnippet ? `blog.${data.attributes.type}` : 'snippet';
-
- let excerpt, cover, shortSliceIndex, authorsData, langIcon, shortText;
-
- if (isBlogSnippet) {
- excerpt = data.attributes.excerpt;
- cover = `${assetPath}${data.attributes.cover}`;
- shortSliceIndex = text.indexOf('\n\n') <= 180
- ? text.indexOf('\n\n')
- : text.indexOf(' ', 160);
- shortText = excerpt && excerpt.trim().length !== 0
- ? excerpt
- : `${text.slice(0, shortSliceIndex)}...`;
- authorsData = getTags(data.attributes.authors).map(a => authors[a]);
- langIcon = langData.find(l => tags.includes(l.language));
- } else
- shortText = text.slice(0, text.indexOf('\n\n'));
-
- const html = parseMarkdown(
- {
- texts: {
- fullDescription: isBlogSnippet ? data.body : text,
- description: shortText,
- },
- codeBlocks: rawCode,
- }, {
- isBlog: isBlogSnippet,
- type,
- assetPath,
- }
- );
-
- const snippetData = {
- ...commonData,
- id: getId(snippet, sourceDir),
- title: data.attributes.title,
- type,
- tags: {
- all: tags,
- primary: tags[0],
- },
- code,
- expertise: isBlogSnippet ? 'blog' : determineExpertiseFromTags(tags),
- text: {
- full: isBlogSnippet ? data.body : text,
- short: shortText,
- },
- cover,
- authors: authorsData,
- icon: langIcon ? langIcon.icon : icon,
- searchTokens: uniqueElements(
- isBlogSnippet ? [
- ...stripExpertiseFromTags(tags),
- ...tokenizeSnippet(`${shortText} ${data.attributes.title}`),
- ].map(v => v.toLowerCase()) : [
- data.attributes.title,
- language.short,
- language.long,
- ...stripExpertiseFromTags(tags),
- ...tokenizeSnippet(shortText),
- ].map(v => v.toLowerCase())
- ).join(' '),
- html,
- ...gitMetadata,
- slug: `/${slugPrefix}${convertToSeoSlug(snippet.slice(0, -3))}`,
- url: `${repoUrlPrefix}/${snippet}`,
- };
-
- snippetData.ranking = rankSnippet({
- ...snippetData,
- language: commonData.language,
- biasPenaltyMultiplier: biasPenaltyMultiplier
- ? biasPenaltyMultiplier
- : 1.0,
- });
-
- const outDir = `${outPath}/${snippetData.slug.slice(1)}`;
- fs.ensureDirSync(outDir);
- fs.writeFileSync(
- `${outDir}/index.json`,
- JSON.stringify({
- template: 'SnippetPage',
- fullRoute: `https://30secondsofcode.org${snippetData.slug}`,
- relRoute: `${snippetData.slug}`,
- priority: (snippetData.ranking * 0.85).toFixed(2),
- }, null, 2)
- );
- fs.writeFileSync(
- `${outDir}/snippet.json`,
- JSON.stringify({
- snippet: transformSnippetContext(snippetData, cardTemplate),
- }, null, 2)
- );
- fs.writeFileSync(
- `${outDir}/metadata.json`,
- JSON.stringify({
- cardTemplate,
- breadcrumbs: transformBreadcrumbs(snippetData, cardTemplate),
- pageDescription: transformSnippetDescription(snippetData, cardTemplate),
- }, null, 2)
- );
-
- const trimmedData = {
- id: snippetData.id,
- tags: snippetData.tags,
- language: {
- long: snippetData.language.long,
- short: snippetData.language.short,
- },
- searchTokens: snippetData.searchTokens,
- ranking: snippetData.ranking,
- blog: snippetData.blog,
- title: snippetData.title,
- expertise: snippetData.expertise,
- icon: snippetData.icon,
- slug: snippetData.slug,
- html: {
- description: snippetData.html.description,
- },
- };
-
- return trimmedData;
-};
-
-export const getParams = (config, langData, assetPath, outPath) => {
- const isCssSnippet = config.dirName === '30css';
- const isBlogSnippet = config.isBlog;
- const hasOptionalLanguage = !isCssSnippet && !isBlogSnippet && config.optionalLanguage && config.optionalLanguage.short;
- const languages = isBlogSnippet ? [] : [
- config.language.short,
- isCssSnippet ? config.secondLanguage.short : null,
- hasOptionalLanguage || isCssSnippet ? config.optionalLanguage.short : null,
- ].filter(Boolean).join('|');
- const icon = config.theme ? config.theme.iconName : null;
- return {
- sourceDir: `${config.dirName}/${config.snippetPath}`,
- commonData: config.commonData,
- slugPrefix: config.slugPrefix,
- language: config.language,
- cardTemplate: config.cardTemplate,
- biasPenaltyMultiplier: config.biasPenaltyMultiplier,
- repoUrlPrefix: config.repoUrlPrefix,
- isCssSnippet, isBlogSnippet, hasOptionalLanguage, languages, icon,
- langData, assetPath, outPath,
- };
-};
-
-/**
- * Synchronously read all snippets and sort them as necessary.
- * The sorting is case-insensitive.
- * @param {string} snippetsPath - The path of the snippets directory.
- * @param {string} assetPath - The public path of the assets directory.
- * @param {string} outPath - The output path of the snippets directory.
- * @param {object} config - The project's enriched configuration
- * (containing the spread config, commonData and prefixes).
- * @param {array} langData - An array of `(language, icon)` tuples.
- * @param {function} boundLog - A bound logger.log function.
- */
-export const readSnippets = async(snippetsPath, assetPath, outPath, config, langData, boundLog) => {
- const snippetFilenames = getFilesInDir(snippetsPath, boundLog);
- const params = getParams(config, langData, assetPath, outPath);
-
- let snippets = [];
- try {
- for (let snippet of snippetFilenames) {
- const snippetData = await parseSnippet(snippetsPath, snippet, params);
- snippets.push(snippetData);
- }
- } catch (err) {
- /* istanbul ignore next */
- boundLog(`Fatal error while reading snippets: ${err}`, 'error');
- boundLog(`Stack trace: ${err.stack}`, 'error');
- /* istanbul ignore next */
- process.exit(1);
- }
- return snippets;
-};
-
-export default readSnippets;
diff --git a/src/yild/extractSnippets/postProcess.js b/src/yild/extractSnippets/postProcess.js
deleted file mode 100644
index 59454becf..000000000
--- a/src/yild/extractSnippets/postProcess.js
+++ /dev/null
@@ -1,278 +0,0 @@
-import fs from 'fs-extra';
-import recommendationEngine from 'engines/recommendationEngine';
-import { transformSnippetIndex } from 'build/transformers';
-import { chunk } from 'utils';
-import EXPERTISE_LEVELS from 'config/expertise';
-import literals from 'lang/en/listing';
-
-const ORDERS_MAP = {
- 'p': literals.orders.popularity,
- 'a': literals.orders.alphabetical,
- 'e': literals.orders.expertise,
-};
-
-const CARDS_PER_PAGE = 40;
-
-const compileListingPages = (
- indexedChunks,
- context,
- baseUrl,
- slugOrderingSegment,
- ordersList
-) => {
- const {
- contentPath: contentOutDir,
- } = global._yild_instance.config.paths;
-
- indexedChunks.forEach((chunk, i, chunks) => {
- const isMainListing = context.listingType === 'main' && slugOrderingSegment === 'p' && i === 0;
- const outDir = `${contentOutDir}${baseUrl}/${slugOrderingSegment}/${i + 1}`;
- fs.ensureDirSync(outDir);
-
- fs.writeFileSync(
- `${outDir}/index.json`,
- JSON.stringify({
- template: 'ListingPage',
- fullRoute: `https://30secondsofcode.org${baseUrl}/${slugOrderingSegment}/${i + 1}`,
- relRoute: `${baseUrl}/${slugOrderingSegment}/${i + 1}`,
- priority: isMainListing ? 1.0 : 0.7,
- }, null, 2)
- );
- fs.writeFileSync(
- `${outDir}/snippetList.json`,
- JSON.stringify({
- snippetList: chunk,
- }, null, 2)
- );
- fs.writeFileSync(
- `${outDir}/metadata.json`,
- JSON.stringify({
- isMainListing,
- paginator: {
- pageNumber: i + 1,
- totalPages: chunks.length,
- baseUrl,
- slugOrderingSegment,
- },
- sorter: {
- orders: ordersList.map(order => (
- {
- url: `${baseUrl}/${order}/1`,
- title: ORDERS_MAP[order],
- }
- )),
- selectedOrder: ORDERS_MAP[slugOrderingSegment],
- },
- ...context,
- }, null, 2)
- );
- });
-};
-
-const compileListingPagesWithOrderOptions = (
- context,
- baseUrl,
- orders,
- chunks,
- contextCustomizer = () => ({})
-) => {
- orders.forEach((order, i) => {
- compileListingPages(
- chunks[i],
- { ...context, ...contextCustomizer(order, i)},
- baseUrl,
- order,
- orders
- );
- });
-};
-
-const compileListingData = (snippetIndex, listingMetas) => {
- // 1. Create listing pages for the main listing:
- // Tranform and chunk data for popularity, alphabetical and expertise ordering
- const transformedIndex = transformSnippetIndex(snippetIndex);
- const popularChunks = chunk(transformedIndex, CARDS_PER_PAGE);
- const alphabeticalChunks = chunk(transformedIndex.sort((a, b) =>
- a.title.localeCompare(b.title)
- ), CARDS_PER_PAGE);
- const expertiseChunks = chunk(transformedIndex.sort((a, b) =>
- a.expertise === b.expertise ? a.title.localeCompare(b.title) :
- !a.expertise ? 1 : !b.expertise ? -1 :
- EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
- ), CARDS_PER_PAGE);
- // Create main listing sublinks and customization method for context
- const mainListingSublinks = listingMetas
- .map(v => v.featured > 0 ? v : {...v, featured: 500 })
- .sort((a, b) => a.featured === b.featured ? a.name - b.name : a.featured - b.featured);
- const mainContextCustomizer = order => {
- return {
- listingSublinks: mainListingSublinks
- .map(l => ({
- ...l,
- url: l.url.replace('/p/1', `/${order}/1`),
- })),
- };
- };
- // Create the listing pages with the order options provided
- compileListingPagesWithOrderOptions(
- {
- listingName: literals.snippetList,
- listingTitle: literals.snippetList,
- listingType: 'main',
- listingSublinks: mainListingSublinks,
- pageDescription: literals.pageDescription('main', {
- snippetCount: transformedIndex.length,
- }),
- },
- '/list',
- ['p', 'a', 'e'],
- [popularChunks, alphabeticalChunks, expertiseChunks],
- mainContextCustomizer
- );
-
- // 2. Create listing pages for the language listings
- listingMetas.forEach(listingMeta => {
- // Determine slug prefix and relevant information, create chunks from data for
- // each of the ordering options
- const slugPrefix = listingMeta.slugPrefix;
- const snippetIndexName = snippetIndex
- .find(s => s.slug.startsWith(`${slugPrefix}`)).language.long || '';
- const snippetIndexSlugData = snippetIndex.filter(s =>
- s.slug.startsWith(`${slugPrefix}`) ||
- (s.blog && s.tags.all.find(t => t.toLowerCase() === snippetIndexName.toLowerCase()))
- );
- const transformedSlugChunks = transformSnippetIndex(snippetIndexSlugData);
- const popularSlugChunks = chunk(transformedSlugChunks, CARDS_PER_PAGE);
- const alphabeticalSlugChunks = chunk(transformedSlugChunks.sort((a, b) =>
- a.title.localeCompare(b.title)
- ), CARDS_PER_PAGE);
- const expertiseSlugChunks = chunk(transformedSlugChunks.sort((a, b) =>
- a.expertise === b.expertise ? a.title.localeCompare(b.title) :
- !a.expertise ? 1 : !b.expertise ? -1 :
- EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
- ), CARDS_PER_PAGE);
- // Determine tag prefixes for the listing
- const snippetIndexTagPrefixes = listingMeta.tags;
- const slugContextCustomizer = order => {
- return {
- listingSublinks: listingMeta.blog ? [] : [
- {
- url: `${slugPrefix}/${order}/1`,
- name: literals.tag('all'),
- selected: true,
- },
- ...listingMeta.tags
- .map(tag => ({
- url: `${slugPrefix}/t/${tag}/${order}/1`,
- name: literals.tag(tag),
- })),
- ],
- };
- };
- // Create the listing pages with the order options provided
- compileListingPagesWithOrderOptions(
- {
- listingName: listingMeta.blog ? literals.blog : literals.codelang(snippetIndexName),
- listingTitle: listingMeta.blog ? literals.blog : literals.codelang(snippetIndexName),
- listingType: listingMeta.blog ? 'blog' : 'language',
- pageDescription: literals.pageDescription(listingMeta.blog ? 'blog' : 'language', {
- snippetCount: snippetIndexSlugData.length,
- listingLanguage: listingMeta.blog ? 'blog' : snippetIndexName,
- }),
- },
- `${slugPrefix}`,
- ['p', 'a', 'e'],
- [popularSlugChunks, alphabeticalSlugChunks, expertiseSlugChunks],
- slugContextCustomizer
- );
-
- // 3. Create listing pages for the tag listings
- snippetIndexTagPrefixes.forEach(tagPrefix => {
- // Determine slug prefix and relevant information, create chunks from data
- // for each of the ordering options
- const snippetIndexTagData = snippetIndex
- .filter(s =>
- s.tags.primary === tagPrefix && s.slug.startsWith(`${slugPrefix}`) ||
- ( s.blog &&
- s.tags.all.find(t => t.toLowerCase() === snippetIndexName.toLowerCase()) &&
- s.tags.all.find(t => t.toLowerCase() === tagPrefix.toLowerCase())
- )
- );
- const transformedTagChunks = transformSnippetIndex(snippetIndexTagData);
- const popularTagChunks = chunk(transformedTagChunks, CARDS_PER_PAGE);
- const alphabeticalTagChunks = chunk(transformedTagChunks.sort((a, b) =>
- a.title.localeCompare(b.title)
- ), CARDS_PER_PAGE);
- const expertiseTagChunks = chunk(transformedTagChunks.sort((a, b) =>
- a.expertise === b.expertise ? a.title.localeCompare(b.title) :
- !a.expertise ? 1 : !b.expertise ? -1 :
- EXPERTISE_LEVELS.indexOf(a.expertise) - EXPERTISE_LEVELS.indexOf(b.expertise)
- ), CARDS_PER_PAGE);
- const tagContextCustomizer = order => {
- return {
- listingSublinks: listingMeta.blog ? [] : [
- {
- url: `${slugPrefix}/${order}/1`,
- name: literals.tag('all'),
- selected: true,
- },
- ...listingMeta.tags
- .map(tag => ({
- url: `${slugPrefix}/t/${tag}/${order}/1`,
- name: literals.tag(tag),
- })),
- ].map(tag => ({ ...tag, selected: tag.url.indexOf(`/t/${tagPrefix}/`) !== -1 })),
- };
- };
- // Create the listing pages with the order options provided
- compileListingPagesWithOrderOptions(
- {
- listingName: literals.codelangTag(snippetIndexName, tagPrefix),
- listingTitle: literals.codelang(snippetIndexName),
- listingType: 'tag',
- pageDescription: literals.pageDescription('tag', {
- snippetCount: snippetIndexSlugData.length,
- listingLanguage: snippetIndexName,
- listingTag: tagPrefix,
- }),
- },
- `${slugPrefix}/t/${tagPrefix}`,
- ['p', 'a', 'e'],
- [popularTagChunks, alphabeticalTagChunks, expertiseTagChunks],
- tagContextCustomizer
- );
- });
- });
-};
-
-const postProcess = (allData, allSnippetData, parentLog) => {
- const boundLog = parentLog.rebind('postProcess');
-
- // Generate listing datas
- compileListingData(allSnippetData, allData.map(({ data }) => data.meta));
-
- // Write snippet recommendations
- return allData.map(async({ snippetsPath, data }) => {
- const {
- contentPath: contentOutDir,
- } = global._yild_instance.config.paths;
- boundLog(`Post-processing snippets for ${snippetsPath}`, 'info');
-
- for (let snippet of data.data) {
- const recommendedSnippets = transformSnippetIndex(
- recommendationEngine(allSnippetData, snippet)
- );
-
- const outDir = `${contentOutDir}/${snippet.slug.slice(1)}`;
- fs.ensureDirSync(outDir);
- await fs.writeFile(
- `${outDir}/recommendations.json`,
- JSON.stringify({
- recommendedSnippets,
- }, null, 2)
- );
- }
- });
-};
-
-export default postProcess;
diff --git a/src/yild/index.js b/src/yild/index.js
deleted file mode 100644
index 6f5638622..000000000
--- a/src/yild/index.js
+++ /dev/null
@@ -1,56 +0,0 @@
-
-import logger, { format } from './logOutput';
-import { actions, helpFlag } from './core';
-
-/**
- * Performs the actions of the given step, using the provided config.
- * @param {object} actions - A set of actions that can be executed.
- * @param {object} config - A configuration object.
- */
-const performStepActions = (actions, config) => stepNo =>
- Object.keys(actions)
- .filter(flagName => actions[flagName].step === stepNo)
- .map(flagName => {
- const matchingArg = config.args.find(arg => actions[flagName].matcher.test(arg));
- if(matchingArg) {
- const param = actions[flagName].param && matchingArg.indexOf('=') !== -1
- ? matchingArg.slice(matchingArg.indexOf('=') + 1)
- : false;
- return actions[flagName].process(param);
- }
- });
-
-/**
- * Run preprocessing tasks based on the given configuration.
- * @param {object} config - A configuration object.
- */
-const yild = async config => {
- global._yild_instance = {
- config,
- env: process.env.NODE_ENV.toUpperCase(),
- };
-
- logger.log(`${format('yild', 'bold')} is starting up...`, 'info');
- logger.logProcessInfo();
- logger.breakLine();
-
- if(config.args.some(arg => helpFlag.test(arg))) {
- logger.logOptionList(actions);
- return;
- }
-
- const performStep = performStepActions(actions, config);
-
- await Promise.all(performStep(0));
- logger.breakLine();
-
- await Promise.all(performStep(1));
- logger.breakLine();
-
- await Promise.all(performStep(2));
- logger.breakLine();
-
- logger.log(`${format('yild', 'bold')} is terminating...`, 'info');
-};
-
-export default yild;
diff --git a/src/yild/makeIcons/cssTemplate.hbs b/src/yild/makeIcons/cssTemplate.hbs
deleted file mode 100644
index 08c02a5e9..000000000
--- a/src/yild/makeIcons/cssTemplate.hbs
+++ /dev/null
@@ -1,32 +0,0 @@
-@font-face {
- font-family: "{{ fontName }}";
- src: {{{ src }}};
-}
-
-{{ baseSelector }}:before {
- font-family: {{ fontName }} !important;
- font-style: normal;
- font-weight: normal !important;
- font-variant: normal;
- text-transform: none;
- line-height: 1;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-{{# each codepoints }}
-{{ ../baseSelector }}.{{ ../classPrefix }}{{ @key }}:before {
- content: "\\{{ this }}";
-}
-{{/ each }}
-
-{{# each langSelectors }}
-{{this}}{{#if @last}} { {{else}}, {{/if}}
-{{/ each}}
-{{# each langIcons }}
- &.{{ ../classPrefix }}{{ this.iconName }} {
- background: {{ this.backColor }};
- color: {{ this.foreColor }};
- }
-{{/ each }}
-}
diff --git a/src/yild/makeIcons/index.js b/src/yild/makeIcons/index.js
deleted file mode 100644
index ff1bf2798..000000000
--- a/src/yild/makeIcons/index.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import glob from 'glob';
-import fs from 'fs-extra';
-import path from 'path';
-import webfontsGenerator from 'webfonts-generator';
-import { initAction, loadContentConfigs } from '../core';
-import iconConfig from 'config/icons';
-
-const {
- types,
- fontName,
- fontRelativePath,
- cssTemplatePath,
- cssSelector,
- cssClassName,
- cssClassPrefix,
- cssLanguageSelectors,
-} = iconConfig;
-
-/**
- * Generate a woff2 fle with the icon font and CSS styles to go with it.
- */
-const makeIcons = () => {
- const [boundLog, , inPath, contentPath, outPath, cssPath] = initAction('makeIcons', [
- ['paths', 'rawIconPath'],
- ['paths', 'rawContentPath'],
- ['paths', 'rawAssetPath'],
- ['paths', 'iconFontPath'],
- ]);
- const files = glob.sync(`${inPath}`);
- const configs = loadContentConfigs(contentPath, boundLog);
- boundLog(`Generating icon font and styles from ${files.length} files...`, 'info');
-
- const config = {
- files,
- dest: outPath,
- fontName,
- types,
- html: false,
- css: true,
- cssDest: cssPath,
- cssFontsUrl: fontRelativePath,
- cssTemplate: cssTemplatePath,
- templateOptions: {
- baseSelector: cssSelector,
- baseClassNames: cssClassName,
- classPrefix: cssClassPrefix,
- langSelectors: cssLanguageSelectors,
- langIcons: configs
- .map(cfg => cfg.theme)
- .filter(Boolean),
- },
- };
-
- return new Promise((resolve, reject) => {
- webfontsGenerator(config, (error, result) => {
- if (error) reject(error);
- else {
- const fileName = `${config.dest}/${config.fontName}`;
- boundLog(`Writing font to ${path.resolve(`${fileName}.${types[0]}`)}...`, 'info');
- ['svg', 'ttf', 'woff'].forEach(suffix => fs.removeSync(`${fileName}.${suffix}`));
- boundLog('Generating icon font and styles complete', 'success');
- resolve(result);
- }
- });
- });
-};
-
-export default makeIcons;
diff --git a/src/yild/prepareAssets/index.js b/src/yild/prepareAssets/index.js
deleted file mode 100644
index 0d2033b47..000000000
--- a/src/yild/prepareAssets/index.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import fs from 'fs-extra';
-import path from 'path';
-import sharp from 'sharp';
-import glob from 'glob';
-import { initAction, loadContentConfigs } from '../core';
-
-const supportedExtensions = [
- 'jpeg', 'jpg', 'png', 'webp', 'tif', 'tiff',
-];
-const maxWidth = 800;
-const outputQuality = 80;
-
-/**
- *
- * @param {string} asset - The filename of the given asset.
- * @param {string} imageDirName - The output directory.
- */
-const processImageAsset = (asset, outDir) =>
- new Promise((resolve, reject) => {
- const fileName = asset.slice(asset.lastIndexOf('/'));
- const img = sharp(asset);
- return img
- .metadata()
- .then(metadata => {
- const resizeWidth = Math.min(maxWidth, metadata.width);
- const format = metadata.format;
- return img
- .resize({ width: resizeWidth })
- .toFormat(format, { quality: outputQuality })
- .toFile(
- `${outDir}/${fileName}`,
- (err, info) => {
- if (err) reject(err);
- else resolve(info);
- }
- );
- });
- });
-
-/**
- * Prepares the assets directory.
- */
-const prepareAssets = async() => {
- const [boundLog, , inPath, outPath, contentPath, staticAssetPath] = initAction(
- 'prepareAssets', [
- ['paths', 'rawAssetPath'], ['paths', 'assetPath'],
- ['paths', 'rawContentPath'], ['paths', 'staticAssetPath'],
- ]
- );
- const configs = loadContentConfigs(contentPath, boundLog);
- boundLog('Processing assets from config...', 'info');
-
- boundLog(`Copying static assets from ${path.resolve(inPath)} to ${path.resolve(outPath)}`, 'info');
- fs.ensureDirSync(outPath);
- await fs.copy(inPath, outPath);
- boundLog('Static assets have been copied', 'success');
-
- boundLog(`Processing image assets from configuration files`, 'info');
- for (const cfg of configs) {
- const { images, dirName } = cfg;
- if (images && images.name && images.path) {
- fs.ensureDirSync(path.join(outPath, images.name));
- const assets = glob
- .sync(`${contentPath}/sources/${dirName}/${images.path}/*.@(${supportedExtensions.join('|')})`)
- .map(file => path.resolve(file));
- await Promise.all(assets.map(asset => processImageAsset(asset, `${outPath}/${images.name}`)));
- }
- }
- boundLog(`Processing image assets from configuration files complete`, 'success');
-
- boundLog(`Copying assets from ${path.resolve(outPath)} to ${path.resolve('static', staticAssetPath)}`, 'info');
- if(global._yild_instance.env === 'PRODUCTION') {
- fs.ensureDirSync(path.join('static', staticAssetPath));
- fs.copySync(outPath, path.join('static', staticAssetPath));
- }
- boundLog(`Copying assets complete`, 'success');
-
- return;
-};
-
-export default prepareAssets;
diff --git a/src/yild/serveSnippets/index.js b/src/yild/serveSnippets/index.js
deleted file mode 100644
index fb10cbb6f..000000000
--- a/src/yild/serveSnippets/index.js
+++ /dev/null
@@ -1,154 +0,0 @@
-import http from 'http';
-import fs from 'fs-extra';
-import path from 'path';
-import { initAction, loadContentConfigs } from '../core';
-import { transformSnippetIndex, transformSnippetContext } from 'build/transformers';
-
-const PORT = 7000;
-
-const MIME_TYPES = {
- jpeg: 'image/jpeg',
- jpg: 'image/jpeg',
- png: 'image/png',
- webp: 'image/webp',
- tif: 'image/tiff',
- tiff: 'image/tiff',
-};
-
-const serveSnippets = () => {
- const [boundLog, , inPath, configsPath, assetPath, staticAssetPath] = initAction(
- 'serveSnippets', [
- ['paths', 'contentPath'], ['paths', 'rawContentPath'],
- ['paths', 'assetPath'], ['paths', 'staticAssetPath'],
- ]
- );
- boundLog('Serving snippets from generated JSON files...', 'info');
-
- const configSlugs = loadContentConfigs(configsPath, boundLog)
- .reduce((acc, cfg) => {
- acc[cfg.slug] = cfg.dirName;
- return acc;
- }, {});
-
- http.createServer((req, res) => {
- if(req.url.indexOf('favicon.ico') !== -1) {
- res.writeHead(404, { 'Content-Type': 'application/json' });
- res.end(JSON.stringify({ status: 404, error: 'Invalid type' }));
- }
- boundLog(`Processing request: ${req.url}`, 'info');
- // Set headers as necessary (Cross-origin etc.)
- res.setHeader('Access-Control-Allow-Origin', '*');
- res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
- res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
-
- const reqUrl = req.url.replace(/\/$/g, '');
- const reqSegments = reqUrl.split('/').filter(Boolean);
-
- const type = reqUrl.toLowerCase().includes(`/${staticAssetPath}/`)
- ? 'asset'
- : 'snippet';
-
- let hasSuffix, repoSegment, cardTemplate, filePath;
-
- switch (type) {
- case 'snippet': {
- hasSuffix = reqUrl.toLowerCase().endsWith('.json');
- repoSegment = hasSuffix ? configSlugs[reqSegments[0].slice(0, -5)] : configSlugs[reqSegments[0]];
- filePath = path.resolve(`${inPath}/${repoSegment}${reqSegments === 1 && hasSuffix ? '' : '.json'}`);
- cardTemplate = reqSegments[0].toLowerCase() === 'blog'
- ? 'BlogSnippetCard'
- : reqSegments[0].toLowerCase() === 'css'
- ? 'CssSnippetCard'
- : 'StandardSnippetCard';
-
- try {
- fs.readFile(filePath, 'utf8', (err, content) => {
- if (err) throw err;
- else {
- try {
- const data = JSON.parse(content).data;
-
- switch (reqSegments.length) {
- case 1:
- res.writeHead(200, { 'Content-Type': 'application/json' });
- res.end(
- JSON.stringify(transformSnippetIndex(data))
- );
- break;
- case 3: {
- const snippetData = data.find(
- s => s.slug === (hasSuffix ? reqUrl.toLowerCase().slice(0, -5) : reqUrl.toLowerCase())
- );
- if(!snippetData) throw 'Snippet does not exist';
- res.writeHead(200, { 'Content-Type': 'application/json' });
- res.end(JSON
- .stringify(
- transformSnippetContext(snippetData, cardTemplate)
- )
- .replace(
- new RegExp(`/${staticAssetPath}/`, 'gi'),
- `http://127.0.0.1:7000/${staticAssetPath}/`
- )
- );
- break;
- }
- default:
- throw 'Invalid path';
- }
- } catch(e) {
- res.writeHead(404, { 'Content-Type': 'application/json' });
- res.end(JSON.stringify({ status: 404, error: e }));
- boundLog(`Encountered an error while processing ${req.url}`, 'error');
- boundLog(`${e}`, 'error');
- }
- }
- });
- } catch(e) {
- res.writeHead(404, { 'Content-Type': 'application/json' });
- res.end(JSON.stringify({ status: 404, error: e }));
- boundLog(`Encountered an error while processing ${req.url}`, 'error');
- boundLog(`${e}`, 'error');
- }
- break;
- }
- case 'asset': {
- filePath = path.resolve(`${assetPath}/${reqSegments.slice(1).join('/')}`);
- const mimeType = MIME_TYPES[reqSegments.slice(-1)[0].split('.').slice(-1)[0]];
- try {
- fs.readFile(filePath, (err, img) => {
- if (err) throw err;
- else {
- res.writeHead(200, {'Content-Type': mimeType });
- res.end(img, 'binary');
- }
- });
- } catch(e) {
- res.writeHead(404, { 'Content-Type': 'application/json' });
- res.end(JSON.stringify({ status: 404, error: e }));
- boundLog(`Encountered an error while processing ${req.url}`, 'error');
- boundLog(`${e}`, 'error');
- }
- break;
- }
- default: {
- res.writeHead(404, { 'Content-Type': 'application/json' });
- res.end(JSON.stringify({ status: 404, error: 'Invalid type' }));
- break;
- }
- }
- boundLog(`Finished processing request: ${req.url}`, 'success');
- }).listen(PORT);
-
- boundLog(`Server running at http://127.0.0.1:${PORT}/`, 'success');
-
- return new Promise(resolve => {
- process.on('SIGINT', () => {
- console.log();
- boundLog('Received SIGINT. Server shutting down...', 'info');
- resolve();
- process.exit();
- });
- });
-};
-
-export default serveSnippets;
From c0838d0d4253d083a4b1c2d9aa0692610a2833ff Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 2 Sep 2020 16:50:32 +0300
Subject: [PATCH 29/39] Update package
Temporarily remove old yild scripts.
---
package.json | 8 --------
1 file changed, 8 deletions(-)
diff --git a/package.json b/package.json
index 5b8fe3f3f..b815f7799 100644
--- a/package.json
+++ b/package.json
@@ -68,15 +68,7 @@
],
"license": "MIT",
"scripts": {
- "extract-snippets": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js -e",
- "watch-snippets": "npm-watch extract-snippets",
- "prepare-assets": "NODE_PATH=src NODE_ENV=development npx --node-arg '-r esm' ./src/jobs/yild.js -e ",
- "watch-assets": "npm-watch prepare-assets",
- "serve-snippets": "NODE_PATH=src NODE_ENV=development npx --node-arg '-r esm' ./src/jobs/yild.js -s",
- "yild": "NODE_PATH=src npx --node-arg '-r esm' ./src/jobs/yild.js",
"prebuild": "NODE_PATH=src NODE_ENV=production npx --node-arg '-r esm' ./src/scripts/build.js",
- "predevelop": "NODE_PATH=src NODE_ENV=development npx --node-arg '-r esm' ./src/jobs/yild.js",
- "pretest": "NODE_PATH=src NODE_ENV=test npx --node-arg '-r esm' ./src/jobs/yild.js",
"build": "NODE_PATH=src npx --node-arg '-r esm' gatsby build",
"develop": "NODE_PATH=src npx --node-arg '-r esm' gatsby develop -p 8000",
"debug": "NODE_PATH=src npx --node-arg '-r esm --nolazy --inspect-brk' node_modules/.bin/gatsby develop",
From ad1b2f04fac8b55d7f2390a164b7bc9d840a3f24 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Wed, 2 Sep 2020 16:52:07 +0300
Subject: [PATCH 30/39] Remove requirables from content configs
---
content/configs/30blog.json | 3 ---
content/configs/30code.json | 3 ---
content/configs/30csharp.json | 3 ---
content/configs/30css.json | 3 ---
content/configs/30dart.json | 3 ---
content/configs/30golang.json | 3 ---
content/configs/30php.json | 3 ---
content/configs/30python.json | 3 ---
content/configs/30react.json | 3 ---
9 files changed, 27 deletions(-)
diff --git a/content/configs/30blog.json b/content/configs/30blog.json
index a2957ba5e..69739d023 100644
--- a/content/configs/30blog.json
+++ b/content/configs/30blog.json
@@ -3,9 +3,6 @@
"dirName": "30blog",
"repoUrl": "https://github.com/30-seconds/30-seconds-blog",
"snippetPath": "blog_posts",
- "requirables": [
- "blog_data/snippets.json"
- ],
"slug": "blog",
"resolver": "blogResolver",
"isBlog": true,
diff --git a/content/configs/30code.json b/content/configs/30code.json
index 5f5d60f21..2e3f344d5 100644
--- a/content/configs/30code.json
+++ b/content/configs/30code.json
@@ -3,9 +3,6 @@
"dirName": "30code",
"repoUrl": "https://github.com/30-seconds/30-seconds-of-code",
"snippetPath": "snippets",
- "requirables": [
- "snippet_data/snippets.json"
- ],
"language": {
"short": "js",
"long": "JavaScript"
diff --git a/content/configs/30csharp.json b/content/configs/30csharp.json
index c8c6d2453..c76edeb49 100644
--- a/content/configs/30csharp.json
+++ b/content/configs/30csharp.json
@@ -3,9 +3,6 @@
"dirName": "30csharp",
"repoUrl": "https://github.com/30-seconds/30-seconds-of-csharp",
"snippetPath": "snippets",
- "requirables": [
- "snippet_data/snippets.json"
- ],
"language": {
"short": "csharp",
"long": "C#"
diff --git a/content/configs/30css.json b/content/configs/30css.json
index 68e0d0f51..7469b8e8e 100644
--- a/content/configs/30css.json
+++ b/content/configs/30css.json
@@ -3,9 +3,6 @@
"dirName": "30css",
"repoUrl": "https://github.com/30-seconds/30-seconds-of-css",
"snippetPath": "snippets",
- "requirables": [
- "snippet_data/snippets.json"
- ],
"language": {
"short": "css",
"long": "CSS"
diff --git a/content/configs/30dart.json b/content/configs/30dart.json
index 26a572353..0c11127ca 100644
--- a/content/configs/30dart.json
+++ b/content/configs/30dart.json
@@ -3,9 +3,6 @@
"dirName": "30dart",
"repoUrl": "https://github.com/30-seconds/30-seconds-of-dart",
"snippetPath": "snippets",
- "requirables": [
- "snippet_data/snippets.json"
- ],
"language": {
"short": "dart",
"long": "Dart"
diff --git a/content/configs/30golang.json b/content/configs/30golang.json
index 2d3572a98..800d43257 100644
--- a/content/configs/30golang.json
+++ b/content/configs/30golang.json
@@ -3,9 +3,6 @@
"dirName": "30golang",
"repoUrl": "https://github.com/30-seconds/30-seconds-of-golang",
"snippetPath": "snippets",
- "requirables": [
- "snippet_data/snippets.json"
- ],
"language": {
"short": "go",
"long": "Go"
diff --git a/content/configs/30php.json b/content/configs/30php.json
index 10fc0340e..99b0a8d70 100644
--- a/content/configs/30php.json
+++ b/content/configs/30php.json
@@ -3,9 +3,6 @@
"dirName": "30php",
"repoUrl": "https://github.com/30-seconds/30-seconds-of-php",
"snippetPath": "snippets",
- "requirables": [
- "snippet_data/snippets.json"
- ],
"language": {
"short": "php",
"long": "PHP"
diff --git a/content/configs/30python.json b/content/configs/30python.json
index 5e35e8ebd..9f3c547e0 100644
--- a/content/configs/30python.json
+++ b/content/configs/30python.json
@@ -3,9 +3,6 @@
"dirName": "30python",
"repoUrl": "https://github.com/30-seconds/30-seconds-of-python",
"snippetPath": "snippets",
- "requirables": [
- "snippet_data/snippets.json"
- ],
"language": {
"short": "py",
"long": "Python"
diff --git a/content/configs/30react.json b/content/configs/30react.json
index 11320aba1..bbdd557cd 100644
--- a/content/configs/30react.json
+++ b/content/configs/30react.json
@@ -3,9 +3,6 @@
"dirName": "30react",
"repoUrl": "https://github.com/30-seconds/30-seconds-of-react",
"snippetPath": "snippets",
- "requirables": [
- "snippet_data/snippets.json"
- ],
"language": {
"short": "jsx",
"long": "React"
From 64db724010cc73d9f9b3b106c3e4586e85472705 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Thu, 3 Sep 2020 16:12:35 +0300
Subject: [PATCH 31/39] Use websiteUrl for routes
---
src/build/json/index.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/build/json/index.js b/src/build/json/index.js
index 5d2a6fd78..f6a928948 100644
--- a/src/build/json/index.js
+++ b/src/build/json/index.js
@@ -1,8 +1,9 @@
import util from 'util';
import fs from 'fs-extra';
+import globalConfig from 'config/global';
const writeFile = util.promisify(fs.writeFile);
-const routePrefix = 'https://30secondsofcode.org';
+const routePrefix = globalConfig.websiteUrl;
/**
* Writes the provided chunks to the specified directory.
From 8d5ad61f1769414a3d1439d813478f0b8aee6bd6 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Thu, 3 Sep 2020 16:13:01 +0300
Subject: [PATCH 32/39] Move parseRequirements into build directory
---
src/build/requirements/index.js | 5 +++++
src/{gatsby => build/requirements}/parseRequirements.js | 2 +-
src/{gatsby => build/requirements}/parseRequirements.test.js | 0
src/gatsby/index.js | 2 +-
4 files changed, 7 insertions(+), 2 deletions(-)
create mode 100644 src/build/requirements/index.js
rename src/{gatsby => build/requirements}/parseRequirements.js (97%)
rename src/{gatsby => build/requirements}/parseRequirements.test.js (100%)
diff --git a/src/build/requirements/index.js b/src/build/requirements/index.js
new file mode 100644
index 000000000..5a10f7230
--- /dev/null
+++ b/src/build/requirements/index.js
@@ -0,0 +1,5 @@
+import { parseRequirements } from './parseRequirements';
+
+export {
+ parseRequirements
+};
diff --git a/src/gatsby/parseRequirements.js b/src/build/requirements/parseRequirements.js
similarity index 97%
rename from src/gatsby/parseRequirements.js
rename to src/build/requirements/parseRequirements.js
index 55ee63e80..9e0f3c699 100644
--- a/src/gatsby/parseRequirements.js
+++ b/src/build/requirements/parseRequirements.js
@@ -33,7 +33,7 @@ export const parseTemplates = (templates, templatesDir) =>
/**
* Returns an object containing templates and requirables.
*/
-const parseRequirements = () => ({
+export const parseRequirements = () => ({
templates: parseTemplates(
isDevelopment ? paths.devTemplates : paths.templates,
paths.templatesPath
diff --git a/src/gatsby/parseRequirements.test.js b/src/build/requirements/parseRequirements.test.js
similarity index 100%
rename from src/gatsby/parseRequirements.test.js
rename to src/build/requirements/parseRequirements.test.js
diff --git a/src/gatsby/index.js b/src/gatsby/index.js
index b69f5b2c8..9273b7bcd 100644
--- a/src/gatsby/index.js
+++ b/src/gatsby/index.js
@@ -1,4 +1,4 @@
-import parseRequirements from './parseRequirements';
+import { parseRequirements } from 'build/requirements';
import createPages from './createPages';
import onCreateWebpackConfig from './onCreateWebpackConfig';
From e10ed300b9c0a3c4649cbf957e0055e7d020ed5b Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Thu, 3 Sep 2020 16:13:14 +0300
Subject: [PATCH 33/39] Change priorities for listings
---
src/build/listing/index.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/build/listing/index.js b/src/build/listing/index.js
index 7349e28c8..296abeb0e 100644
--- a/src/build/listing/index.js
+++ b/src/build/listing/index.js
@@ -32,9 +32,9 @@ export const compileListingPages = async(
const isTopLevelListingFirstPage = isTopLevelListing && isFirstPage;
const isMainTagListing = context.listingType === 'tag' && isFirstPage;
const priority = isMainListingFirstPage ? 1.0
- : (isTopLevelListingFirstPage || isMainListing) ? 0.9
- : (isMainTagListing || isTopLevelListing) ? 0.8
- : 0.7;
+ : (isTopLevelListingFirstPage || isMainListing) ? 0.75
+ : (isMainTagListing || isTopLevelListing) ? 0.5
+ : 0.25;
const outDir = `${contentOutDir}${baseUrl}/${slugOrderingSegment}/${i + 1}`;
await writeChunks(
From f1c57fad78bce31c7a9319ad0cf66345b9c8bd42 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Thu, 3 Sep 2020 16:13:45 +0300
Subject: [PATCH 34/39] Generate sitemap for routes
---
.gitignore | 1 +
src/build/sitemap/index.js | 29 +++++++++++++++++++++++++++
src/build/sitemap/sitemapTemplate.hbs | 6 ++++++
src/config/paths.json | 1 +
src/config/sitemap.json | 3 +++
src/scripts/build.js | 9 +++++++++
6 files changed, 49 insertions(+)
create mode 100644 src/build/sitemap/index.js
create mode 100644 src/build/sitemap/sitemapTemplate.hbs
create mode 100644 src/config/sitemap.json
diff --git a/.gitignore b/.gitignore
index b06cafd85..9a0821a1b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,3 +114,4 @@ public
.content
content/data
static/assets
+src/xml/sitemap.xml
diff --git a/src/build/sitemap/index.js b/src/build/sitemap/index.js
new file mode 100644
index 000000000..3dbe564ff
--- /dev/null
+++ b/src/build/sitemap/index.js
@@ -0,0 +1,29 @@
+import util from 'util';
+import fs from 'fs-extra';
+import handlebars from 'handlebars';
+import { parseRequirements } from 'build/requirements';
+import { bindLogger } from 'build/core';
+
+const writeFile = util.promisify(fs.writeFile);
+
+export const generateSitemap = async() => {
+ const boundLog = bindLogger('makeIcons');
+ const { sitemapTemplatePath } = global.yild.sitemap;
+ const { xmlPath } = global.yild.paths;
+ const template = handlebars.compile(
+ fs.readFileSync(sitemapTemplatePath, 'utf-8')
+ );
+ const requirables = parseRequirements().requirables;
+ boundLog(`Generating sitemap for ${requirables.length} routes`, 'info');
+
+ const sitemap = template({
+ nodes: [
+ { fullRoute: global.yild.mainConfig.websiteUrl, priority: 1.0},
+ ...requirables.filter(n => !n.relRoute.endsWith('404')),
+ ],
+ });
+
+ await writeFile(`${xmlPath}sitemap.xml`, sitemap);
+
+ boundLog('Generating sitemap complete', 'success');
+};
diff --git a/src/build/sitemap/sitemapTemplate.hbs b/src/build/sitemap/sitemapTemplate.hbs
new file mode 100644
index 000000000..5871be064
--- /dev/null
+++ b/src/build/sitemap/sitemapTemplate.hbs
@@ -0,0 +1,6 @@
+
+
+{{# each nodes }}
+ {{ this.fullRoute }} daily {{ this.priority }}
+{{/ each }}
+
diff --git a/src/config/paths.json b/src/config/paths.json
index 4c57fdd79..3f7eb39d5 100644
--- a/src/config/paths.json
+++ b/src/config/paths.json
@@ -8,6 +8,7 @@
"rawIconPath": "src/icons/*.svg",
"iconFontPath": "src/styles/_icons.scss",
"queryPath": "./src/queries",
+ "xmlPath": "./src/xml",
"templatesPath": "./src/components/templates",
"templates": [
{
diff --git a/src/config/sitemap.json b/src/config/sitemap.json
new file mode 100644
index 000000000..86150a3aa
--- /dev/null
+++ b/src/config/sitemap.json
@@ -0,0 +1,3 @@
+{
+ "sitemapTemplatePath": "src/build/sitemap/sitemapTemplate.hbs"
+}
diff --git a/src/scripts/build.js b/src/scripts/build.js
index 9d042d05c..37324e753 100644
--- a/src/scripts/build.js
+++ b/src/scripts/build.js
@@ -2,14 +2,19 @@ import { logger, format } from 'build/core';
import { loadContentConfigs } from 'build/config';
import { updateContent } from 'build/content';
import { makeIcons, prepareAssets } from 'build/assets';
+import { generateSitemap } from 'build/sitemap';
import { extractData } from 'build/extract';
+import globalConfig from 'config/global';
import pathConfig from 'config/paths';
import iconConfig from 'config/icons';
+import sitemapConfig from 'config/sitemap';
export const build = async() => {
global.yild = global.yild || {};
global.yild.paths = pathConfig;
global.yild.icons = iconConfig;
+ global.yild.sitemap = sitemapConfig;
+ global.yild.mainConfig = globalConfig;
global.yild.env = 'PRODUCTION';
logger.log(`${format('yild', 'bold')} is starting up...`, 'info');
@@ -26,6 +31,10 @@ export const build = async() => {
extractData(),
prepareAssets(),
]);
+
+ await Promise.all([
+ generateSitemap(),
+ ]);
};
build();
From 1fc1f8c46ea85af5b170140cce72e25925875222 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Thu, 3 Sep 2020 16:45:15 +0300
Subject: [PATCH 35/39] Add opensearch xml
---
src/components/organisms/meta/index.jsx | 6 ++++++
src/xml/opensearch.xml | 7 +++++++
2 files changed, 13 insertions(+)
create mode 100644 src/xml/opensearch.xml
diff --git a/src/components/organisms/meta/index.jsx b/src/components/organisms/meta/index.jsx
index 1e84d17ff..a7ee4db6c 100644
--- a/src/components/organisms/meta/index.jsx
+++ b/src/components/organisms/meta/index.jsx
@@ -200,6 +200,12 @@ const Meta = ({
key="preconnect-google-analytics"
href="https://www.google-analytics.com"
/>
+
{
canonical ?
+30 seconds of code
+30s Search>
+30secondsofcode@gmail.com
+UTF-8
+
+
From 6d17f4e6df034db467fd04bf04444471bfd45207 Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Thu, 3 Sep 2020 16:58:59 +0300
Subject: [PATCH 36/39] Copy static XMLs onPostBuild
---
gatsby-node.js | 2 ++
src/build/sitemap/index.js | 2 +-
src/components/organisms/meta/index.jsx | 5 +++++
src/gatsby/index.js | 2 ++
src/gatsby/onPostBuild.js | 12 ++++++++++++
5 files changed, 22 insertions(+), 1 deletion(-)
create mode 100644 src/gatsby/onPostBuild.js
diff --git a/gatsby-node.js b/gatsby-node.js
index 8a3df2bc5..21e19c32b 100644
--- a/gatsby-node.js
+++ b/gatsby-node.js
@@ -2,6 +2,7 @@ const { green } = require('chalk');
const {
createPages,
onCreateWebpackConfig,
+ onPostBuild,
parseRequirements,
} = require(`./src/gatsby`);
@@ -10,3 +11,4 @@ console.log(`${green('success')} parse requirements`);
exports.createPages = createPages(templates, requirables);
exports.onCreateWebpackConfig = onCreateWebpackConfig;
+exports.onPostBuild = onPostBuild;
diff --git a/src/build/sitemap/index.js b/src/build/sitemap/index.js
index 3dbe564ff..81160e914 100644
--- a/src/build/sitemap/index.js
+++ b/src/build/sitemap/index.js
@@ -23,7 +23,7 @@ export const generateSitemap = async() => {
],
});
- await writeFile(`${xmlPath}sitemap.xml`, sitemap);
+ await writeFile(`${xmlPath}/sitemap.xml`, sitemap);
boundLog('Generating sitemap complete', 'success');
};
diff --git a/src/components/organisms/meta/index.jsx b/src/components/organisms/meta/index.jsx
index a7ee4db6c..d074d1a22 100644
--- a/src/components/organisms/meta/index.jsx
+++ b/src/components/organisms/meta/index.jsx
@@ -200,6 +200,11 @@ const Meta = ({
key="preconnect-google-analytics"
href="https://www.google-analytics.com"
/>
+
{
+ console.log('aacaca');
+ fs.copySync(paths.xmlPath, 'public');
+};
+
+export default onPostBuild;
From 39d69afeeaa3814db9ab7d5357d3af8d6074e88d Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Thu, 3 Sep 2020 17:00:23 +0300
Subject: [PATCH 37/39] Remove gatsby-plugin-sitemap
Use home-brewed solution.
---
gatsby-config.js | 1 -
package-lock.json | 30 ------------------------------
package.json | 1 -
3 files changed, 32 deletions(-)
diff --git a/gatsby-config.js b/gatsby-config.js
index 2617a10bd..ce116fb69 100644
--- a/gatsby-config.js
+++ b/gatsby-config.js
@@ -11,7 +11,6 @@ module.exports = {
},
plugins: [
`gatsby-plugin-resolve-src`,
- `gatsby-plugin-sitemap`,
{
resolve: `gatsby-source-filesystem`,
options: {
diff --git a/package-lock.json b/package-lock.json
index acecdd38a..fe4a1a358 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14226,26 +14226,6 @@
}
}
},
- "gatsby-plugin-sitemap": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/gatsby-plugin-sitemap/-/gatsby-plugin-sitemap-2.3.1.tgz",
- "integrity": "sha512-v7MeRsqt2NDr+HuTfJ3coEFtFNNdBabZ6s8NBdEE9yOBYMRm0Fi28MYgXe0UtAXX3I8I/eVmv8zJP6HH0rU1jA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.8.7",
- "minimatch": "^3.0.4",
- "pify": "^3.0.0",
- "sitemap": "^1.13.0"
- },
- "dependencies": {
- "pify": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
- "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
- "dev": true
- }
- }
- },
"gatsby-react-router-scroll": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/gatsby-react-router-scroll/-/gatsby-react-router-scroll-2.3.1.tgz",
@@ -24751,16 +24731,6 @@
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
"dev": true
},
- "sitemap": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-1.13.0.tgz",
- "integrity": "sha1-Vpy+IYAgKSamKiZs094Jyc60P4M=",
- "dev": true,
- "requires": {
- "underscore": "^1.7.0",
- "url-join": "^1.1.0"
- }
- },
"slash": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
diff --git a/package.json b/package.json
index b815f7799..637d6ea19 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,6 @@
"gatsby-plugin-react-helmet": "^3.1.23",
"gatsby-plugin-resolve-src": "^2.0.0",
"gatsby-plugin-sass": "^2.1.30",
- "gatsby-plugin-sitemap": "^2.2.28",
"gatsby-source-filesystem": "^2.1.51",
"glob": "^7.1.6",
"hast-util-to-html": "^7.1.1",
From adf765a51627bccbffe17e4ccd815da6bbc84d1b Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Sun, 6 Sep 2020 12:18:02 +0300
Subject: [PATCH 38/39] Deprecate devTemplates
---
src/build/requirements/parseRequirements.js | 2 +-
.../templates/listingPage/index.dev.jsx | 11 ------
.../templates/snippetPage/index.dev.jsx | 11 ------
src/components/templates/withLiveReload.jsx | 38 -------------------
src/config/paths.json | 26 -------------
5 files changed, 1 insertion(+), 87 deletions(-)
delete mode 100644 src/components/templates/listingPage/index.dev.jsx
delete mode 100644 src/components/templates/snippetPage/index.dev.jsx
delete mode 100644 src/components/templates/withLiveReload.jsx
diff --git a/src/build/requirements/parseRequirements.js b/src/build/requirements/parseRequirements.js
index 9e0f3c699..54f7e655b 100644
--- a/src/build/requirements/parseRequirements.js
+++ b/src/build/requirements/parseRequirements.js
@@ -35,7 +35,7 @@ export const parseTemplates = (templates, templatesDir) =>
*/
export const parseRequirements = () => ({
templates: parseTemplates(
- isDevelopment ? paths.devTemplates : paths.templates,
+ paths.templates,
paths.templatesPath
),
requirables: parseRequirables(paths.contentPath),
diff --git a/src/components/templates/listingPage/index.dev.jsx b/src/components/templates/listingPage/index.dev.jsx
deleted file mode 100644
index 5f809fb3d..000000000
--- a/src/components/templates/listingPage/index.dev.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-/* eslint-disable react/prop-types */
-/* istanbul ignore next */
-import withLiveReload from 'components/templates/withLiveReload';
-import ListingPage from './index';
-
-export default ({ location, ...rest }) => withLiveReload(
- ListingPage,
- location.pathname,
- true,
- rest
-);
diff --git a/src/components/templates/snippetPage/index.dev.jsx b/src/components/templates/snippetPage/index.dev.jsx
deleted file mode 100644
index 43f4ed7e1..000000000
--- a/src/components/templates/snippetPage/index.dev.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-/* eslint-disable react/prop-types */
-/* istanbul ignore next */
-import withLiveReload from 'components/templates/withLiveReload';
-import SnippetPage from './index';
-
-export default ({ location, ...rest }) => withLiveReload(
- SnippetPage,
- location.pathname,
- false,
- rest
-);
diff --git a/src/components/templates/withLiveReload.jsx b/src/components/templates/withLiveReload.jsx
deleted file mode 100644
index 587c92b2a..000000000
--- a/src/components/templates/withLiveReload.jsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/* eslint-disable react/prop-types */
-/* istanbul ignore next */
-import React, { useState } from 'react';
-import { useInterval } from 'components/hooks';
-
-const withLiveReload = (WrappedComponent, url, isListing, props) => {
- const [fetchedData, setFetchedData] = useState({});
- useInterval(() => {
- fetch(`http://127.0.0.1:7000${url}`)
- .then(res => res.json())
- .then(data => setFetchedData(data));
- }, 5000);
-
- const _props = Object.keys(fetchedData).length
- ? isListing ? {
- ...props,
- pageContext: {
- ...props.pageContext,
- snippetList: {
- ...props.pageContext.snippetList,
- ...fetchedData,
- },
- },
- } : {
- ...props,
- pageContext: {
- ...props.pageContext,
- snippet: {
- ...props.pageContext.snippet,
- ...fetchedData,
- },
- },
- } : props;
-
- return ;
-};
-
-export default withLiveReload;
diff --git a/src/config/paths.json b/src/config/paths.json
index 3f7eb39d5..dda43cc47 100644
--- a/src/config/paths.json
+++ b/src/config/paths.json
@@ -35,31 +35,5 @@
"name": "SettingsPage",
"path": "settingsPage/index.jsx"
}
- ],
- "devTemplates": [
- {
- "name": "SnippetPage",
- "path": "snippetPage/index.dev.jsx"
- },
- {
- "name": "SearchPage",
- "path": "searchPage/index.jsx"
- },
- {
- "name": "ListingPage",
- "path": "listingPage/index.dev.jsx"
- },
- {
- "name": "NotFoundPage",
- "path": "notFoundPage/index.jsx"
- },
- {
- "name": "StaticPage",
- "path": "staticPage/index.jsx"
- },
- {
- "name": "SettingsPage",
- "path": "settingsPage/index.jsx"
- }
]
}
From a36e787ccd8a15cebf4f0fa7ea6c9ba2a8abb47a Mon Sep 17 00:00:00 2001
From: Chalarangelo
Date: Sun, 6 Sep 2020 12:19:11 +0300
Subject: [PATCH 39/39] Deprecate watch for development mode
Will introduce new system in the future.
---
Procfile | 6 -
package-lock.json | 562 ----------------------------------------------
package.json | 22 --
3 files changed, 590 deletions(-)
delete mode 100644 Procfile
diff --git a/Procfile b/Procfile
deleted file mode 100644
index e2ca93151..000000000
--- a/Procfile
+++ /dev/null
@@ -1,6 +0,0 @@
-# Run dev scripts concurrently
-gatsby: npm run develop
-watch-snippets: npm run watch-snippets
-watch-assets: npm run watch-assets
-serve: npm run serve-snippets
-# test: npm run test:watch
diff --git a/package-lock.json b/package-lock.json
index fe4a1a358..718c2324f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6101,12 +6101,6 @@
"rsvp": "^4.8.4"
}
},
- "capture-stack-trace": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz",
- "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==",
- "dev": true
- },
"case": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz",
@@ -7346,15 +7340,6 @@
}
}
},
- "create-error-class": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
- "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
- "dev": true,
- "requires": {
- "capture-stack-trace": "^1.0.0"
- }
- },
"create-hash": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
@@ -14609,15 +14594,6 @@
"process": "^0.11.10"
}
},
- "global-dirs": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz",
- "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=",
- "dev": true,
- "requires": {
- "ini": "^1.3.4"
- }
- },
"global-modules": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
@@ -15569,12 +15545,6 @@
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
"dev": true
},
- "ignore-by-default": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
- "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=",
- "dev": true
- },
"immer": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz",
@@ -16700,16 +16670,6 @@
"integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
"dev": true
},
- "is-installed-globally": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz",
- "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=",
- "dev": true,
- "requires": {
- "global-dirs": "^0.1.0",
- "is-path-inside": "^1.0.0"
- }
- },
"is-invalid-path": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-invalid-path/-/is-invalid-path-0.1.0.tgz",
@@ -16803,15 +16763,6 @@
}
}
},
- "is-path-inside": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
- "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
- "dev": true,
- "requires": {
- "path-is-inside": "^1.0.1"
- }
- },
"is-plain-obj": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
@@ -16833,12 +16784,6 @@
"integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
"dev": true
},
- "is-redirect": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
- "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=",
- "dev": true
- },
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
@@ -19942,436 +19887,6 @@
}
}
},
- "nodemon": {
- "version": "1.19.4",
- "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz",
- "integrity": "sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==",
- "dev": true,
- "requires": {
- "chokidar": "^2.1.8",
- "debug": "^3.2.6",
- "ignore-by-default": "^1.0.1",
- "minimatch": "^3.0.4",
- "pstree.remy": "^1.1.7",
- "semver": "^5.7.1",
- "supports-color": "^5.5.0",
- "touch": "^3.1.0",
- "undefsafe": "^2.0.2",
- "update-notifier": "^2.5.0"
- },
- "dependencies": {
- "ansi-align": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
- "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
- "dev": true,
- "requires": {
- "string-width": "^2.0.0"
- }
- },
- "ansi-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
- "dev": true
- },
- "boxen": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
- "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==",
- "dev": true,
- "requires": {
- "ansi-align": "^2.0.0",
- "camelcase": "^4.0.0",
- "chalk": "^2.0.1",
- "cli-boxes": "^1.0.0",
- "string-width": "^2.0.0",
- "term-size": "^1.2.0",
- "widest-line": "^2.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- }
- }
- },
- "camelcase": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
- "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
- "dev": true
- },
- "chokidar": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
- "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
- "dev": true,
- "requires": {
- "anymatch": "^2.0.0",
- "async-each": "^1.0.1",
- "braces": "^2.3.2",
- "fsevents": "^1.2.7",
- "glob-parent": "^3.1.0",
- "inherits": "^2.0.3",
- "is-binary-path": "^1.0.0",
- "is-glob": "^4.0.0",
- "normalize-path": "^3.0.0",
- "path-is-absolute": "^1.0.0",
- "readdirp": "^2.2.1",
- "upath": "^1.1.1"
- }
- },
- "ci-info": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz",
- "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
- "dev": true
- },
- "cli-boxes": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
- "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=",
- "dev": true
- },
- "configstore": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz",
- "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==",
- "dev": true,
- "requires": {
- "dot-prop": "^4.1.0",
- "graceful-fs": "^4.1.2",
- "make-dir": "^1.0.0",
- "unique-string": "^1.0.0",
- "write-file-atomic": "^2.0.0",
- "xdg-basedir": "^3.0.0"
- }
- },
- "cross-spawn": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
- "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
- "dev": true,
- "requires": {
- "lru-cache": "^4.0.1",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
- }
- },
- "crypto-random-string": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
- "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=",
- "dev": true
- },
- "debug": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- },
- "dot-prop": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
- "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==",
- "dev": true,
- "requires": {
- "is-obj": "^1.0.0"
- }
- },
- "execa": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
- "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
- "dev": true,
- "requires": {
- "cross-spawn": "^5.0.1",
- "get-stream": "^3.0.0",
- "is-stream": "^1.1.0",
- "npm-run-path": "^2.0.0",
- "p-finally": "^1.0.0",
- "signal-exit": "^3.0.0",
- "strip-eof": "^1.0.0"
- }
- },
- "glob-parent": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
- "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
- "dev": true,
- "requires": {
- "is-glob": "^3.1.0",
- "path-dirname": "^1.0.0"
- },
- "dependencies": {
- "is-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
- "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.0"
- }
- }
- }
- },
- "got": {
- "version": "6.7.1",
- "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz",
- "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
- "dev": true,
- "requires": {
- "create-error-class": "^3.0.0",
- "duplexer3": "^0.1.4",
- "get-stream": "^3.0.0",
- "is-redirect": "^1.0.0",
- "is-retry-allowed": "^1.0.0",
- "is-stream": "^1.0.0",
- "lowercase-keys": "^1.0.0",
- "safe-buffer": "^5.0.1",
- "timed-out": "^4.0.0",
- "unzip-response": "^2.0.1",
- "url-parse-lax": "^1.0.0"
- }
- },
- "is-ci": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
- "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
- "dev": true,
- "requires": {
- "ci-info": "^1.5.0"
- }
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
- "dev": true
- },
- "is-npm": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz",
- "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=",
- "dev": true
- },
- "is-obj": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
- "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
- "dev": true
- },
- "latest-version": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz",
- "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=",
- "dev": true,
- "requires": {
- "package-json": "^4.0.0"
- }
- },
- "lru-cache": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
- "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
- "dev": true,
- "requires": {
- "pseudomap": "^1.0.2",
- "yallist": "^2.1.2"
- }
- },
- "make-dir": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
- "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
- "dev": true,
- "requires": {
- "pify": "^3.0.0"
- }
- },
- "package-json": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz",
- "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=",
- "dev": true,
- "requires": {
- "got": "^6.7.1",
- "registry-auth-token": "^3.0.1",
- "registry-url": "^3.0.3",
- "semver": "^5.1.0"
- }
- },
- "pify": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
- "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
- "dev": true
- },
- "prepend-http": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
- "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
- "dev": true
- },
- "registry-auth-token": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz",
- "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==",
- "dev": true,
- "requires": {
- "rc": "^1.1.6",
- "safe-buffer": "^5.0.1"
- }
- },
- "registry-url": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
- "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
- "dev": true,
- "requires": {
- "rc": "^1.0.1"
- }
- },
- "shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
- "dev": true,
- "requires": {
- "shebang-regex": "^1.0.0"
- }
- },
- "shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
- "dev": true
- },
- "string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "requires": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- }
- },
- "strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true,
- "requires": {
- "ansi-regex": "^3.0.0"
- }
- },
- "term-size": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
- "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=",
- "dev": true,
- "requires": {
- "execa": "^0.7.0"
- }
- },
- "unique-string": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz",
- "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=",
- "dev": true,
- "requires": {
- "crypto-random-string": "^1.0.0"
- }
- },
- "update-notifier": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz",
- "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==",
- "dev": true,
- "requires": {
- "boxen": "^1.2.1",
- "chalk": "^2.0.1",
- "configstore": "^3.0.0",
- "import-lazy": "^2.1.0",
- "is-ci": "^1.0.10",
- "is-installed-globally": "^0.1.0",
- "is-npm": "^1.0.0",
- "latest-version": "^3.0.0",
- "semver-diff": "^2.0.0",
- "xdg-basedir": "^3.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- }
- }
- },
- "url-parse-lax": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz",
- "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=",
- "dev": true,
- "requires": {
- "prepend-http": "^1.0.1"
- }
- },
- "which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "widest-line": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz",
- "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
- "dev": true,
- "requires": {
- "string-width": "^2.1.1"
- }
- },
- "write-file-atomic": {
- "version": "2.4.3",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
- "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.11",
- "imurmurhash": "^0.1.4",
- "signal-exit": "^3.0.2"
- }
- },
- "xdg-basedir": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
- "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=",
- "dev": true
- }
- }
- },
"noms": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz",
@@ -20476,16 +19991,6 @@
}
}
},
- "npm-watch": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/npm-watch/-/npm-watch-0.6.0.tgz",
- "integrity": "sha512-qt3jZd8gKX45m5czKv/CsxzWDMgblu/meL5PefeoViq07e8l7+DBNC8RgHAI0DfA+jJq2n/pJLaNL4yfHR+0qw==",
- "dev": true,
- "requires": {
- "nodemon": "^1.18.7",
- "through2": "^2.0.0"
- }
- },
"npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
@@ -22319,12 +21824,6 @@
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
"dev": true
},
- "pstree.remy": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
- "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
- "dev": true
- },
"public-encrypt": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
@@ -24378,15 +23877,6 @@
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
},
- "semver-diff": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz",
- "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=",
- "dev": true,
- "requires": {
- "semver": "^5.0.3"
- }
- },
"send": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
@@ -26443,26 +25933,6 @@
"integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=",
"dev": true
},
- "touch": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
- "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
- "dev": true,
- "requires": {
- "nopt": "~1.0.10"
- },
- "dependencies": {
- "nopt": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
- "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
- "dev": true,
- "requires": {
- "abbrev": "1"
- }
- }
- }
- },
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
@@ -26666,32 +26136,6 @@
"integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
"dev": true
},
- "undefsafe": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz",
- "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==",
- "dev": true,
- "requires": {
- "debug": "^2.2.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
- }
- }
- },
"underscore": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz",
@@ -26988,12 +26432,6 @@
"integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
"dev": true
},
- "unzip-response": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
- "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=",
- "dev": true
- },
"upath": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
diff --git a/package.json b/package.json
index 637d6ea19..802c91a5e 100644
--- a/package.json
+++ b/package.json
@@ -43,7 +43,6 @@
"jest-transform-stub": "^2.0.0",
"mdast-util-to-hast": "^9.1.0",
"node-sass": "^4.14.1",
- "npm-watch": "^0.6.0",
"prismjs": "^1.19.0",
"prop-types": "^15.7.2",
"react": "^16.13.0",
@@ -80,27 +79,6 @@
"test:e2e": "CYPRESS_SUPPORT=y npm run build && start-server-and-test serve http://localhost:9000 cy:open",
"test:e2e-ci": "CYPRESS_SUPPORT=y npm run build && start-server-and-test serve http://localhost:9000 cy:run"
},
- "watch": {
- "extract-snippets": {
- "patterns": [
- "content/sources"
- ],
- "extensions": "md",
- "delay": "5000",
- "ignore": "README",
- "quiet": true,
- "runOnChangeOnly": true
- },
- "prepare-assets": {
- "patterns": [
- "content/sources"
- ],
- "extensions": "jpeg,jpg,png,webp,tif,tiff",
- "delay": "5000",
- "quiet": true,
- "runOnChangeOnly": true
- }
- },
"repository": {
"type": "git",
"url": "https://github.com/30-seconds/30-seconds-web"