diff --git a/example/index.html b/example/index.html
index b311e0fd..240266cc 100644
--- a/example/index.html
+++ b/example/index.html
@@ -18,6 +18,9 @@
},
"2015-02-16-this-is-a-toml-frontmatter-post.md": {
content: "+++\ntitle = \"This is a TOML front matter post\"\nimage = \"/nf-logo.png\"\n\"date\" = \"2015-02-16T00:00:00.000Z\"\n+++\n\n# I Am a Title in Markdown\n\nHello, world\n\n* One Thing\n* Another Thing\n* A Third Thing\n"
+ },
+ "2015-02-14-this-is-a-post-with-a-different-extension.other": {
+ content: "---\ntitle: This post should not appear because the extension is different\nimage: /nf-logo.png\ndate: 2015-02-14T00:00:00.000Z\n---\n\n# I Am a Title in Markdown\n\nHello, world\n\n* One Thing\n* Another Thing\n* A Third Thing\n"
}
},
_faqs: {
diff --git a/src/backends/backend.js b/src/backends/backend.js
index 0001eaba..cddeab18 100644
--- a/src/backends/backend.js
+++ b/src/backends/backend.js
@@ -2,7 +2,7 @@ import TestRepoBackend from "./test-repo/implementation";
import GitHubBackend from "./github/implementation";
import NetlifyAuthBackend from "./netlify-auth/implementation";
import { resolveFormat } from "../formats/formats";
-import { selectListMethod, selectEntrySlug, selectEntryPath, selectAllowNewEntries } from "../reducers/collections";
+import { selectListMethod, selectEntrySlug, selectEntryPath, selectAllowNewEntries, selectFolderEntryExtension } from "../reducers/collections";
import { createEntry } from "../valueObjects/Entry";
class LocalStorageAuthStore {
@@ -82,7 +82,8 @@ class Backend {
listEntries(collection) {
const listMethod = this.implementation[selectListMethod(collection)];
- return listMethod.call(this.implementation, collection)
+ const extension = selectFolderEntryExtension(collection);
+ return listMethod.call(this.implementation, collection, extension)
.then(loadedEntries => (
loadedEntries.map(loadedEntry => createEntry(
collection.get("name"),
diff --git a/src/backends/github/API.js b/src/backends/github/API.js
index b856ea3e..ef7765bf 100644
--- a/src/backends/github/API.js
+++ b/src/backends/github/API.js
@@ -155,7 +155,14 @@ export default class API {
listFiles(path) {
return this.request(`${ this.repoURL }/contents/${ path }`, {
params: { ref: this.branch },
- });
+ })
+ .then(files => {
+ if (!Array.isArray(files)) {
+ throw new Error(`Cannot list files, path ${path} is not a directory but a ${files.type}`);
+ }
+ return files;
+ })
+ .then(files => files.filter(file => file.type === "file"));
}
readUnpublishedBranchFile(contentKey) {
diff --git a/src/backends/github/implementation.js b/src/backends/github/implementation.js
index 0c1d982f..c3c77731 100644
--- a/src/backends/github/implementation.js
+++ b/src/backends/github/implementation.js
@@ -1,6 +1,7 @@
import semaphore from "semaphore";
import AuthenticationPage from "./AuthenticationPage";
import API from "./API";
+import { fileExtension } from '../../lib/pathHelper'
const MAX_CONCURRENT_DOWNLOADS = 10;
@@ -39,8 +40,9 @@ export default class GitHub {
return Promise.resolve(this.token);
}
- entriesByFolder(collection) {
+ entriesByFolder(collection, extension) {
return this.api.listFiles(collection.get("folder"))
+ .then(files => files.filter(fileExtension(file.name) === extension))
.then(this.fetchFiles);
}
diff --git a/src/backends/test-repo/implementation.js b/src/backends/test-repo/implementation.js
index f00d9916..0c3ab1a5 100644
--- a/src/backends/test-repo/implementation.js
+++ b/src/backends/test-repo/implementation.js
@@ -1,4 +1,5 @@
import AuthenticationPage from './AuthenticationPage';
+import { fileExtension } from '../../lib/pathHelper'
function getFile(path) {
const segments = path.split('/');
@@ -40,11 +41,15 @@ export default class TestRepo {
return Promise.resolve('');
}
- entriesByFolder(collection) {
+ entriesByFolder(collection, extension) {
const entries = [];
const folder = collection.get('folder');
if (folder) {
for (const path in window.repoFiles[folder]) {
+ if (fileExtension(path) !== extension) {
+ continue;
+ }
+
const file = { path: `${ folder }/${ path }` };
entries.push(
{
diff --git a/src/formats/__tests__/toml.md b/src/formats/__tests__/toml.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/lib/__tests__/pathHelper.spec.js b/src/lib/__tests__/pathHelper.spec.js
new file mode 100644
index 00000000..5a947057
--- /dev/null
+++ b/src/lib/__tests__/pathHelper.spec.js
@@ -0,0 +1,101 @@
+import { fileExtensionWithSeparator, fileExtension } from '../pathHelper';
+
+describe('fileExtensionWithSeparator', () => {
+ it('should return the extension of a file', () => {
+ expect(
+ fileExtensionWithSeparator('index.html')
+ ).toEqual(
+ '.html'
+ );
+ });
+
+ it('should return the extension of a file path', () => {
+ expect(
+ fileExtensionWithSeparator('/src/main/index.html')
+ ).toEqual(
+ '.html'
+ );
+ });
+
+ it('should return the extension of a file path with trailing slash', () => {
+ expect(
+ fileExtensionWithSeparator('/src/main/index.html/')
+ ).toEqual(
+ '.html'
+ );
+ });
+
+ it('should return the extension for an extension with two ..', () => {
+ expect(
+ fileExtensionWithSeparator('/src/main/index..html')
+ ).toEqual(
+ '.html'
+ );
+ });
+
+ it('should return an empty string for the parent path ..', () => {
+ expect(
+ fileExtensionWithSeparator('..')
+ ).toEqual(
+ ''
+ );
+ });
+
+ it('should return an empty string if the file has no extension', () => {
+ expect(
+ fileExtensionWithSeparator('/src/main/index')
+ ).toEqual(
+ ''
+ );
+ });
+});
+
+describe('fileExtension', () => {
+ it('should return the extension of a file', () => {
+ expect(
+ fileExtension('index.html')
+ ).toEqual(
+ 'html'
+ );
+ });
+
+ it('should return the extension of a file path', () => {
+ expect(
+ fileExtension('/src/main/index.html')
+ ).toEqual(
+ 'html'
+ );
+ });
+
+ it('should return the extension of a file path with trailing slash', () => {
+ expect(
+ fileExtension('/src/main/index.html/')
+ ).toEqual(
+ 'html'
+ );
+ });
+
+ it('should return the extension for an extension with two ..', () => {
+ expect(
+ fileExtension('/src/main/index..html')
+ ).toEqual(
+ 'html'
+ );
+ });
+
+ it('should return an empty string for the parent path ..', () => {
+ expect(
+ fileExtension('..')
+ ).toEqual(
+ ''
+ );
+ });
+
+ it('should return an empty string if the file has no extension', () => {
+ expect(
+ fileExtension('/src/main/index')
+ ).toEqual(
+ ''
+ );
+ });
+});
diff --git a/src/lib/pathHelper.js b/src/lib/pathHelper.js
index 57bb0031..4748122e 100644
--- a/src/lib/pathHelper.js
+++ b/src/lib/pathHelper.js
@@ -58,11 +58,11 @@ export function basename(p, ext = "") {
* last portion of the path. If there is no '.' in the last portion of the path
* or the first character of it is '.', then it returns an empty string.
* @example Usage example
- * path.extname('index.html')
+ * path.fileExtensionWithSeparator('index.html')
* // returns
* '.html'
*/
-export function extname(p) {
+export function fileExtensionWithSeparator(p) {
p = normalizePath(p);
const sections = p.split('/');
p = sections.pop();
@@ -79,3 +79,17 @@ export function extname(p) {
}
return p.substr(i);
}
+
+/**
+ * Return the extension of the path, from after the last '.' to end of string in the
+ * last portion of the path. If there is no '.' in the last portion of the path
+ * or the first character of it is '.', then it returns an empty string.
+ * @example Usage example
+ * path.fileExtension('index.html')
+ * // returns
+ * 'html'
+ */
+export function fileExtension(p) {
+ const ext = fileExtensionWithSeparator(p);
+ return ext === '' ? ext : ext.substr(1);
+}
diff --git a/src/reducers/collections.js b/src/reducers/collections.js
index 35a83064..4cf076c8 100644
--- a/src/reducers/collections.js
+++ b/src/reducers/collections.js
@@ -88,6 +88,7 @@ const selectors = {
};
export const selectFields = (collection, slug) => selectors[collection.get('type')].fields(collection, slug);
+export const selectFolderEntryExtension = (collection) => selectors[FOLDER].entryExtension(collection);
export const selectEntryPath = (collection, slug) => selectors[collection.get('type')].entryPath(collection, slug);
export const selectEntrySlug = (collection, path) => selectors[collection.get('type')].entrySlug(collection, path);
export const selectListMethod = collection => selectors[collection.get('type')].listMethod();