diff --git a/package-lock.json b/package-lock.json index 6ca32cd98c..251cf8d085 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4589,6 +4589,18 @@ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, + "gray-matter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.1.tgz", + "integrity": "sha512-p0MADBEBl1CohV7nRZ8sVinBexEe3CKVhh0A0QIHKpcbRoxB0VgeMpRPjW/HBHIPLAKrpIIIm5mZ6hKu3E+iQg==", + "dev": true, + "requires": { + "js-yaml": "^3.11.0", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + } + }, "growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", @@ -6728,9 +6740,9 @@ } }, "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, "lodash._reinterpolate": { @@ -8774,6 +8786,27 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "semver": { "version": "5.5.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", @@ -9273,6 +9306,12 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, + "strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", + "dev": true + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", diff --git a/package.json b/package.json index e0cc5c179f..4aff45fdaa 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "test-ci": "npm test", "test:client": "cd ./client && npm test && cd ../", "test:curriculum": "echo 'Warning: TODO - Define Testing.'", - "test:guide:directorys": "node ./tools/scripts/ci/ensure-guide-page-naming.js", + "test:guide-directorys": "node ./tools/scripts/ci/ensure-guide-page-naming.js", "test:server": "echo 'Warning: TODO - Define Testing.'", "test:tools": "jest ./tools", "start-develop": "node ./tools/scripts/start-develop.js" @@ -23,8 +23,10 @@ "debug": "^4.0.1", "dotenv": "^6.0.0", "eslint-config-freecodecamp": "^1.1.1", + "gray-matter": "^4.0.1", "jest": "^23.6.0", "lerna": "^3.4.0", + "lodash": "^4.17.11", "npm-run-all": "^4.1.3", "readdirp-walk": "^1.6.0", "tree-kill": "^1.2.0" diff --git a/tools/scripts/ci/ensure-guide-page-naming.js b/tools/scripts/ci/ensure-guide-page-naming.js index 5fe0e9d0c3..040a77fc22 100644 --- a/tools/scripts/ci/ensure-guide-page-naming.js +++ b/tools/scripts/ci/ensure-guide-page-naming.js @@ -1,6 +1,8 @@ const path = require('path'); const fs = require('fs'); const readdirp = require('readdirp-walk'); +const matter = require('gray-matter'); +const _ = require('lodash'); const guideRoot = path.resolve(__dirname, '../../../guide'); @@ -13,37 +15,6 @@ const allowedLangDirNames = [ 'spanish' ]; -function checkDirName(dirName, fullPath) { - if (dirName.replace(/(\s|\_)/, '') !== dirName) { - throw new Error(` -Invalid character found in '${dirName}', please use '-' for spaces - - Found in: - ${fullPath} -`); - } - if (dirName.toLowerCase() !== dirName) { - throw new Error(` -Upper case characters found in ${dirName}, all folder names must be lower case - - Found in : - ${fullPath} -`); - } -} - -function checkFileName(fileName, fullPath) { - if (fileName !== 'index.md') { - throw new Error( - `${fileName} is not a valid file name, please use 'index.md' - - Found in: - ${fullPath} -` - ); - } -} - function checkFile(file) { const { stat, depth, name, fullPath } = file; if (depth === 1) { @@ -55,14 +26,118 @@ function checkFile(file) { } } if (stat.isDirectory()) { - return checkDirName(name, fullPath); + return checkDirName(name, fullPath).catch(err => { + throw err; + }); } - return checkFileName(name, fullPath); + return checkFileName(name, fullPath) + .then(() => checkFrontmatter(fullPath)) + .catch(err => { + console.log(` + + The below occured in: + + ${fullPath} + + `); + console.error(err); + // eslint-disable-next-line no-process-exit + process.exit(1); + }); } readdirp({ root: guideRoot }) .on('data', checkFile) .on('end', () => { - /* eslint-disable no-process-exit */ + console.log(` + + guide directory naming checks complete + +`); + // eslint-disable-next-line no-process-exit process.exit(0); }); + +function checkDirName(dirName, fullPath) { + return new Promise((resolve, reject) => { + if (dirName.replace(/(\s|\_)/, '') !== dirName) { + return reject( + new Error(` + Invalid character found in '${dirName}', please use '-' for spaces + + Found in: + ${fullPath} + `) + ); + } + if (dirName.toLowerCase() !== dirName) { + return reject( + new Error(` +Upper case characters found in ${dirName}, all folder names must be lower case + + Found in : + ${fullPath} +`) + ); + } + return resolve(); + }); +} + +function checkFileName(fileName, fullPath) { + return new Promise((resolve, reject) => { + if (fileName !== 'index.md') { + return reject( + new Error( + `${fileName} is not a valid file name, please use 'index.md' + + Found in: + ${fullPath} + ` + ) + ); + } + return resolve(); + }); +} + +function checkFrontmatter(fullPath) { + return new Promise((resolve, reject) => + fs.readFile(fullPath, 'utf8', (err, content) => { + if (err) { + return reject(new Error(err)); + } + try { + const { data: frontmatter } = matter(content); + if (!frontmatter || _.isEmpty(frontmatter) || !frontmatter.title) { + return reject( + new Error(` + The article at: ${fullPath} is missing frontmatter. + + Example: + + --- + title: The Article Title + localeTitle: The Translated Title # Only required for translations + --- + + < The Article Body > + + `) + ); + // process.exit(1); + } + return resolve(); + } catch (e) { + console.log(` + + The below occured in: + + ${fullPath} + + `); + throw e; + } + }) + ); +}