feat(guide): Import guide in to the client app

This commit is contained in:
Bouncey
2018-10-04 14:47:55 +01:00
committed by Stuart Taylor
parent 2723a943c9
commit 6e728ce16d
4338 changed files with 148283 additions and 4200 deletions

View File

@ -0,0 +1,55 @@
const crypto = require('crypto');
const path = require('path');
const commonREs = require('../../utils/regEx');
const readDir = require('../../utils/readDir');
const { isAStubRE } = commonREs;
const pagesDir = path.resolve(__dirname, '../../src/pages/guide');
function withGuidePrefix(str) {
return `/guide${str}`;
}
exports.createNavigationNode = node => {
const {
fileAbsolutePath,
frontmatter: { title },
internal: { content },
parent
} = node;
const nodeDir = fileAbsolutePath.replace(/\/index\.md$/, '');
const dashedName = nodeDir.split('/').slice(-1)[0];
const [, path] = nodeDir.split(pagesDir);
const parentPath = path
.split('/')
.slice(0, -1)
.join('/');
const categoryChildren = readDir(nodeDir);
const navNode = {
categoryChildren,
hasChildren: !!categoryChildren.length,
dashedName,
isStubbed: isAStubRE.test(content),
path: withGuidePrefix(path),
parentPath: withGuidePrefix(parentPath),
title
};
const gatsbyRequired = {
id: fileAbsolutePath + ' >>> NavigationNode',
parent,
children: [],
internal: {
type: 'NavigationNode',
contentDigest: crypto
.createHash('md5')
.update(JSON.stringify(navNode))
.digest('hex')
}
};
return { ...navNode, ...gatsbyRequired };
};

View File

@ -0,0 +1,77 @@
const path = require('path');
const { expect } = require('chai');
const { createNavigationNode } = require('./create-navigation-node');
describe('fcc-create-nav-data', () => {
describe('create-vanigation-node', () => {
const mockNode = {
internal: {
content:
'---\ntitle: File Writing\n---\n## File Writing\n\nThis is a stub.' +
" <a href='https://github.com/freecodecamp/guides/tree/master/src/" +
"pages/php/functions/files/writing/index.md' target='_blank' " +
"rel='nofollow'>Help our community expand it</a>.\n\n<a href=" +
"'https://github.com/freecodecamp/guides/blob/master/README.md' " +
"target='_blank' rel='nofollow'>This quick style guide will help " +
'ensure your pull request gets accepted</a>.\n\n<!-- The article ' +
'goes here, in GitHub-flavored Markdown. Feel free to add YouTube ' +
'videos, images, and CodePen/JSBin embeds -->\n\n#### More ' +
'Information:\n<!-- Please add any articles you think might be ' +
'helpful to read before writing the article -->\n'
},
frontmatter: {
title: 'File Writing'
},
fileAbsolutePath: path.resolve(
__dirname,
'../../src/pages/guide/php/functions/files/file-writing/index.md'
)
};
const result = createNavigationNode(mockNode);
it('should return an object', () => {
expect(result).to.be.an('object');
});
it('node.children should be an array', () => {
expect(result.categoryChildren).to.be.an('array');
});
it('node.dashedName should equal the containing folder name', () => {
expect(result.dashedName).equal('file-writing');
});
it('node.path should equal the file path from pagesDir, prefixed with `/guide`', () => {
expect(result.path).to.equal('/guide/php/functions/files/file-writing');
});
it('node.parentPath should equal the path of the parent page, prefixed with `/guide`', () => {
expect(result.parentPath).to.equal('/guide/php/functions/files');
});
it('node.title should equal srcNode.frontmatter.title', () => {
expect(result.title).to.equal(mockNode.frontmatter.title);
});
it('node.isStubbed should be a boolean', () => {
expect(result.isStubbed).to.be.a('boolean');
});
it('node.isStubbed should be true for a stubbed article', () => {
expect(result.isStubbed).to.equal(true);
});
it('node.isStubbed should be false for a non-stubbed article', () => {
const notAStub = {
...mockNode,
internal: {
content: 'this is not a stub article. Infact, it is very informative'
}
};
const result = createNavigationNode(notAStub);
expect(result.isStubbed).to.equal(false);
});
});
});

View File

@ -0,0 +1,13 @@
const { createNavigationNode } = require('./create-navigation-node');
exports.onCreateNode = ({ actions, node }) => {
const { internal: {type, identity}} = node;
if (type === 'MarkdownRemark' && identity === 'guideMarkdown') {
if (node.fileAbsolutePath.includes('LICENSE.md')) {
return null;
}
const { createNode } = actions;
return Promise.resolve(createNavigationNode(node)).then(createNode);
}
return null;
};

View File

@ -0,0 +1,12 @@
{
"name": "fcc-create-nav-data",
"version": "0.0.1",
"scripts": {
"test": "mocha -R spec \"./{,!(node_modules)/**/}*.test.js\"",
"test:watch": "mocha -R spec \"./{,!(node_modules)/**/}*.test.js\" --watch"
},
"dependencies": {
"chai": "^4.1.2",
"mocha": "^5.0.5"
}
}

View File

@ -0,0 +1,170 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
assertion-error@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
browser-stdout@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
chai@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c"
dependencies:
assertion-error "^1.0.1"
check-error "^1.0.1"
deep-eql "^3.0.0"
get-func-name "^2.0.0"
pathval "^1.0.0"
type-detect "^4.0.0"
check-error@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
commander@2.11.0:
version "2.11.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
debug@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies:
ms "2.0.0"
deep-eql@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
dependencies:
type-detect "^4.0.0"
diff@3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
escape-string-regexp@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
get-func-name@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
glob@7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
growl@1.10.3:
version "1.10.3"
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f"
has-flag@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
he@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
brace-expansion "^1.1.7"
minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
mkdirp@0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
minimist "0.0.8"
mocha@^5.0.5:
version "5.0.5"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.0.5.tgz#e228e3386b9387a4710007a641f127b00be44b52"
dependencies:
browser-stdout "1.3.1"
commander "2.11.0"
debug "3.1.0"
diff "3.5.0"
escape-string-regexp "1.0.5"
glob "7.1.2"
growl "1.10.3"
he "1.1.1"
mkdirp "0.5.1"
supports-color "4.4.0"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
dependencies:
wrappy "1"
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
pathval@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
supports-color@4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e"
dependencies:
has-flag "^2.0.0"
type-detect@^4.0.0:
version "4.0.8"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"

View File

@ -11,17 +11,18 @@ that delivers challenge files to the plugin
const { createNode } = actions;
const { source } = pluginOptions;
return source().subscribe(
challenges =>
return source()
.then(challenges =>
challenges
.filter(challenge => challenge.superBlock !== 'Certificates')
.map(challenge => createChallengeNodes(challenge, reporter))
.map(node => createNode(node)),
e =>
.map(node => createNode(node))
)
.catch(e =>
reporter.panic(`fcc-sourec-challenges
${e.message}
${e.message}
`)
);
`)
);
};

View File

@ -0,0 +1,30 @@
const visit = require('unist-util-visit');
const emojiRE = /^:[a-z_]+:$/;
function markdownToHTML(node) {
const { url, title, alt } = node;
const html = `
<img
alt="${alt}"
class="forum-image"
src="${url}"
title="${title}"
>
`;
return Object.assign(node, {
type: 'html',
value: html
});
}
module.exports = ({ markdownAST }) => {
visit(markdownAST, 'image', imageNode => {
if (emojiRE.test(imageNode.title)) {
return markdownToHTML(imageNode);
}
return imageNode;
});
};

View File

@ -0,0 +1,5 @@
{
"name": "gatsby-remark-fcc-forum-emoji",
"description": "A plugin to help fix the styling of forum emoji in the Guide",
"main": "index.js"
}

View File

@ -0,0 +1,16 @@
exports.onCreateNode = ({ node, reporter }, { predicate, identity }) => {
if (typeof predicate !== 'function') {
reporter.panic(
'Please supply a predicate function to `gatsby-plugin-identity`'
);
}
if (typeof identity !== 'string' || identity.lenght === 0) {
reporter.panic(
'`gatsby-plugin-identity` requires an identify string to add to nodes ' +
'that match the predicate'
);
}
if (predicate(node)) {
node.internal.identity = identity;
}
};

View File

@ -0,0 +1 @@
{"name": "gatsby-plugin-node-identity", "version": "0.1.0"}