From a2e8602fdd93cae7f577505f6c7a6a7388d683c4 Mon Sep 17 00:00:00 2001 From: Joseph Earl Date: Fri, 7 Apr 2017 22:40:30 +0100 Subject: [PATCH 1/3] Add multi-format frontmatter parser --- example/index.html | 8 +- package.json | 3 + src/formats/__tests__/toml.md | 0 .../__tests__/yaml-frontmatter.spec.js | 105 ++++++++++++++++++ src/formats/yaml-frontmatter.js | 30 ++--- yarn.lock | 49 +++++++- 6 files changed, 177 insertions(+), 18 deletions(-) create mode 100644 src/formats/__tests__/toml.md create mode 100644 src/formats/__tests__/yaml-frontmatter.spec.js diff --git a/example/index.html b/example/index.html index 6ab62374..b311e0fd 100644 --- a/example/index.html +++ b/example/index.html @@ -11,7 +11,13 @@ window.repoFiles = { _posts: { "2015-02-14-this-is-a-post.md": { - content: "---\ntitle: This is a post\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" + content: "---\ntitle: This is a YAML front matter post\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" + }, + "2015-02-15-this-is-a-json-frontmatter-post.md": { + content: "{\n\"title\": \"This is a JSON front matter post\",\n\"image\": \"/nf-logo.png\",\n\"date\": \"2015-02-15T00: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-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" } }, _faqs: { diff --git a/package.json b/package.json index 2ea0f589..36c7a3ec 100644 --- a/package.json +++ b/package.json @@ -113,6 +113,9 @@ "netlify-auth-js": "^0.5.5", "normalize.css": "^4.2.0", "pluralize": "^3.0.0", + "preliminaries": "^1.0.0", + "preliminaries-parser-toml": "1.0.1", + "preliminaries-parser-yaml": "^1.0.0", "prismjs": "^1.5.1", "prosemirror-commands": "^0.16.0", "prosemirror-history": "^0.16.0", diff --git a/src/formats/__tests__/toml.md b/src/formats/__tests__/toml.md new file mode 100644 index 00000000..e69de29b diff --git a/src/formats/__tests__/yaml-frontmatter.spec.js b/src/formats/__tests__/yaml-frontmatter.spec.js new file mode 100644 index 00000000..11e827f4 --- /dev/null +++ b/src/formats/__tests__/yaml-frontmatter.spec.js @@ -0,0 +1,105 @@ +import YAMLFrontmatter from '../yaml-frontmatter'; + +const YamlFrontmatterFormatter = new YAMLFrontmatter(); + +describe('YAMLFrontmatter', () => { + it('should parse YAML with --- delimiters', () => { + expect( + YamlFrontmatterFormatter.fromFile('---\ntitle: YAML\ndescription: Something longer\n---\nContent') + ).toEqual( + { + title: 'YAML', + description: 'Something longer', + body: 'Content', + } + ); + }); + + it('should parse YAML with ---yaml delimiters', () => { + expect( + YamlFrontmatterFormatter.fromFile('---yaml\ntitle: YAML\ndescription: Something longer\n---\nContent') + ).toEqual( + { + title: 'YAML', + description: 'Something longer', + body: 'Content', + } + ); + }); + + it('should overwrite any body param in the front matter', () => { + expect( + YamlFrontmatterFormatter.fromFile('---\ntitle: The Title\nbody: Something longer\n---\nContent') + ).toEqual( + { + title: 'The Title', + body: 'Content', + } + ); + }); + + it('should parse TOML with +++ delimiters', () => { + expect( + YamlFrontmatterFormatter.fromFile('+++\ntitle = "TOML"\ndescription = "Front matter"\n+++\nContent') + ).toEqual( + { + title: 'TOML', + description: 'Front matter', + body: 'Content', + } + ); + }); + + it('should parse TOML with ---toml delimiters', () => { + expect( + YamlFrontmatterFormatter.fromFile('---toml\ntitle = "TOML"\ndescription = "Something longer"\n---\nContent') + ).toEqual( + { + title: 'TOML', + description: 'Something longer', + body: 'Content', + } + ); + }); + + it('should parse JSON with { } delimiters', () => { + expect( + YamlFrontmatterFormatter.fromFile('{\n"title": "The Title",\n"description": "Something longer"\n}\nContent') + ).toEqual( + { + title: 'The Title', + description: 'Something longer', + body: 'Content', + } + ); + }); + + it('should parse JSON with ---json delimiters', () => { + expect( + YamlFrontmatterFormatter.fromFile('---json\n{\n"title": "The Title",\n"description": "Something longer"\n}\n---\nContent') + ).toEqual( + { + title: 'The Title', + description: 'Something longer', + body: 'Content', + } + ); + }); + + it('should stringify YAML with --- delimiters', () => { + expect( + YamlFrontmatterFormatter.toFile({ body: 'Some content\nOn another line', tags: ['front matter', 'yaml'], title: 'YAML' }) + ).toEqual( + [ + '---', + 'tags:', + ' - front matter', + ' - yaml', + 'title: YAML', + '---', + 'Some content', + 'On another line\n', + ].join('\n') + ); + }); +}); diff --git a/src/formats/yaml-frontmatter.js b/src/formats/yaml-frontmatter.js index bba0a6fe..3d2eb175 100644 --- a/src/formats/yaml-frontmatter.js +++ b/src/formats/yaml-frontmatter.js @@ -1,31 +1,31 @@ -import YAML from './yaml'; +import preliminaries from 'preliminaries'; +import yamlParser from 'preliminaries-parser-yaml'; +import tomlParser from 'preliminaries-parser-toml'; -const regexp = /^---\n([^]*?)\n---\n([^]*)$/; +// Automatically register parsers +preliminaries(true); +yamlParser(true); +tomlParser(true); export default class YAMLFrontmatter { fromFile(content) { - const match = content.match(regexp); - const obj = match ? new YAML().fromFile(match[1]) : {}; - obj.body = match ? (match[2] || '').replace(/^\n+/, '') : content; - return obj; + const result = preliminaries.parse(content); + const data = result.data; + data.body = result.content; + return data; } toFile(data, sortedKeys) { const meta = {}; let body = ''; - let content = ''; - for (var key in data) { + Object.keys(data).forEach((key) => { if (key === 'body') { body = data[key]; } else { meta[key] = data[key]; } - } - - content += '---\n'; - content += new YAML().toFile(meta, sortedKeys); - content += '---\n\n'; - content += body; - return content; + }); + // always stringify to YAML + return preliminaries.stringify(body, meta, { lang: 'yaml', delims: '---' }); } } diff --git a/yarn.lock b/yarn.lock index 5a9ccb9a..2c215a4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2773,6 +2773,10 @@ esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" +esprima@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + esprima@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" @@ -2936,6 +2940,12 @@ express@^4.13.3: utils-merge "1.0.0" vary "~1.1.0" +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + extend@^3.0.0, extend@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" @@ -3870,7 +3880,7 @@ is-es2016-keyword@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-es2016-keyword/-/is-es2016-keyword-1.0.0.tgz#f6e54e110c5e4f8d265e69d2ed0eaf8cf5f47718" -is-extendable@^0.1.1: +is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -4555,7 +4565,14 @@ js-tokens@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" -js-yaml@3.x, js-yaml@^3.4.2, js-yaml@^3.4.3, js-yaml@^3.5.1, js-yaml@^3.7.0: +js-yaml@3.x, js-yaml@^3.4.2, js-yaml@^3.4.3, js-yaml@^3.5.1, js-yaml@^3.8.1: + version "3.8.3" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766" + dependencies: + argparse "^1.0.7" + esprima "^3.1.1" + +js-yaml@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" dependencies: @@ -6779,6 +6796,26 @@ pre-commit@^1.1.3: spawn-sync "^1.0.15" which "1.2.x" +preliminaries-parser-toml@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/preliminaries-parser-toml/-/preliminaries-parser-toml-1.0.1.tgz#009cadc4d801428a05eada48d8ec438a3f690a5f" + dependencies: + toml "^2.3.2" + toml-js "0.0.8" + +preliminaries-parser-yaml@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/preliminaries-parser-yaml/-/preliminaries-parser-yaml-1.0.0.tgz#80da4ed54278fdf2f1e9ce379ab6cdce15cd7b54" + dependencies: + extend-shallow "^2.0.1" + js-yaml "^3.8.1" + +preliminaries@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/preliminaries/-/preliminaries-1.0.0.tgz#973aead5fbc2c8371bcba7de4413c3e8afe16cc1" + dependencies: + extend-shallow "^2.0.1" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -8556,6 +8593,14 @@ to-fast-properties@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" +toml-js@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/toml-js/-/toml-js-0.0.8.tgz#648ea6f1a4d63b19c0bb30b8ed03e40d09473b0a" + +toml@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/toml/-/toml-2.3.2.tgz#5eded5ca42887924949fd06eb0e955656001e834" + topbar@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/topbar/-/topbar-0.1.3.tgz#c9ef8776dc4469f7840e6416f4136ddeccf4b7c6" From dc313d157b457ce4a0ddc2166475d52d2877adf9 Mon Sep 17 00:00:00 2001 From: Joseph Earl Date: Sun, 9 Apr 2017 19:32:33 +0100 Subject: [PATCH 2/3] Rename YamlFrontmatter to just Frontmatter --- ...rontmatter.spec.js => frontmatter.spec.js} | 22 +++++++++---------- src/formats/formats.js | 18 +++++++-------- .../{yaml-frontmatter.js => frontmatter.js} | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) rename src/formats/__tests__/{yaml-frontmatter.spec.js => frontmatter.spec.js} (63%) rename src/formats/{yaml-frontmatter.js => frontmatter.js} (94%) diff --git a/src/formats/__tests__/yaml-frontmatter.spec.js b/src/formats/__tests__/frontmatter.spec.js similarity index 63% rename from src/formats/__tests__/yaml-frontmatter.spec.js rename to src/formats/__tests__/frontmatter.spec.js index 11e827f4..000653e3 100644 --- a/src/formats/__tests__/yaml-frontmatter.spec.js +++ b/src/formats/__tests__/frontmatter.spec.js @@ -1,11 +1,11 @@ -import YAMLFrontmatter from '../yaml-frontmatter'; +import Frontmatter from '../frontmatter'; -const YamlFrontmatterFormatter = new YAMLFrontmatter(); +const FrontmatterFormatter = new Frontmatter(); -describe('YAMLFrontmatter', () => { +describe('Frontmatter', () => { it('should parse YAML with --- delimiters', () => { expect( - YamlFrontmatterFormatter.fromFile('---\ntitle: YAML\ndescription: Something longer\n---\nContent') + FrontmatterFormatter.fromFile('---\ntitle: YAML\ndescription: Something longer\n---\nContent') ).toEqual( { title: 'YAML', @@ -17,7 +17,7 @@ describe('YAMLFrontmatter', () => { it('should parse YAML with ---yaml delimiters', () => { expect( - YamlFrontmatterFormatter.fromFile('---yaml\ntitle: YAML\ndescription: Something longer\n---\nContent') + FrontmatterFormatter.fromFile('---yaml\ntitle: YAML\ndescription: Something longer\n---\nContent') ).toEqual( { title: 'YAML', @@ -29,7 +29,7 @@ describe('YAMLFrontmatter', () => { it('should overwrite any body param in the front matter', () => { expect( - YamlFrontmatterFormatter.fromFile('---\ntitle: The Title\nbody: Something longer\n---\nContent') + FrontmatterFormatter.fromFile('---\ntitle: The Title\nbody: Something longer\n---\nContent') ).toEqual( { title: 'The Title', @@ -40,7 +40,7 @@ describe('YAMLFrontmatter', () => { it('should parse TOML with +++ delimiters', () => { expect( - YamlFrontmatterFormatter.fromFile('+++\ntitle = "TOML"\ndescription = "Front matter"\n+++\nContent') + FrontmatterFormatter.fromFile('+++\ntitle = "TOML"\ndescription = "Front matter"\n+++\nContent') ).toEqual( { title: 'TOML', @@ -52,7 +52,7 @@ describe('YAMLFrontmatter', () => { it('should parse TOML with ---toml delimiters', () => { expect( - YamlFrontmatterFormatter.fromFile('---toml\ntitle = "TOML"\ndescription = "Something longer"\n---\nContent') + FrontmatterFormatter.fromFile('---toml\ntitle = "TOML"\ndescription = "Something longer"\n---\nContent') ).toEqual( { title: 'TOML', @@ -64,7 +64,7 @@ describe('YAMLFrontmatter', () => { it('should parse JSON with { } delimiters', () => { expect( - YamlFrontmatterFormatter.fromFile('{\n"title": "The Title",\n"description": "Something longer"\n}\nContent') + FrontmatterFormatter.fromFile('{\n"title": "The Title",\n"description": "Something longer"\n}\nContent') ).toEqual( { title: 'The Title', @@ -76,7 +76,7 @@ describe('YAMLFrontmatter', () => { it('should parse JSON with ---json delimiters', () => { expect( - YamlFrontmatterFormatter.fromFile('---json\n{\n"title": "The Title",\n"description": "Something longer"\n}\n---\nContent') + FrontmatterFormatter.fromFile('---json\n{\n"title": "The Title",\n"description": "Something longer"\n}\n---\nContent') ).toEqual( { title: 'The Title', @@ -88,7 +88,7 @@ describe('YAMLFrontmatter', () => { it('should stringify YAML with --- delimiters', () => { expect( - YamlFrontmatterFormatter.toFile({ body: 'Some content\nOn another line', tags: ['front matter', 'yaml'], title: 'YAML' }) + FrontmatterFormatter.toFile({ body: 'Some content\nOn another line', tags: ['front matter', 'yaml'], title: 'YAML' }) ).toEqual( [ '---', diff --git a/src/formats/formats.js b/src/formats/formats.js index de357e8a..6eafb5d9 100644 --- a/src/formats/formats.js +++ b/src/formats/formats.js @@ -1,32 +1,32 @@ import YAML from './yaml'; import JSONFormatter from './json'; -import YAMLFrontmatter from './yaml-frontmatter'; +import Frontmatter from './frontmatter'; const yamlFormatter = new YAML(); const jsonFormatter = new JSONFormatter(); -const YamlFrontmatterFormatter = new YAMLFrontmatter(); +const FrontmatterFormatter = new Frontmatter(); function formatByType(type) { // Right now the only type is "editorialWorkflow" and // we always returns the same format - return YamlFrontmatterFormatter; + return FrontmatterFormatter; } export function formatByExtension(extension) { return { yml: yamlFormatter, json: jsonFormatter, - md: YamlFrontmatterFormatter, - markdown: YamlFrontmatterFormatter, - html: YamlFrontmatterFormatter, - }[extension] || YamlFrontmatterFormatter; + md: FrontmatterFormatter, + markdown: FrontmatterFormatter, + html: FrontmatterFormatter, + }[extension] || FrontmatterFormatter; } function formatByName(name) { return { yaml: yamlFormatter, - frontmatter: YamlFrontmatterFormatter, - }[name] || YamlFrontmatterFormatter; + frontmatter: FrontmatterFormatter, + }[name] || FrontmatterFormatter; } export function resolveFormat(collectionOrEntity, entry) { diff --git a/src/formats/yaml-frontmatter.js b/src/formats/frontmatter.js similarity index 94% rename from src/formats/yaml-frontmatter.js rename to src/formats/frontmatter.js index 3d2eb175..a469810c 100644 --- a/src/formats/yaml-frontmatter.js +++ b/src/formats/frontmatter.js @@ -7,7 +7,7 @@ preliminaries(true); yamlParser(true); tomlParser(true); -export default class YAMLFrontmatter { +export default class Frontmatter { fromFile(content) { const result = preliminaries.parse(content); const data = result.data; From 5a5a4f5b123b6bb07fcd90ccb7acb69ecb396b16 Mon Sep 17 00:00:00 2001 From: Joseph Earl Date: Sun, 9 Apr 2017 20:05:00 +0100 Subject: [PATCH 3/3] Update to latest preliminaries --- package.json | 6 +++--- yarn.lock | 29 ++++++++++------------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 36c7a3ec..a0c1a1bd 100644 --- a/package.json +++ b/package.json @@ -113,9 +113,9 @@ "netlify-auth-js": "^0.5.5", "normalize.css": "^4.2.0", "pluralize": "^3.0.0", - "preliminaries": "^1.0.0", - "preliminaries-parser-toml": "1.0.1", - "preliminaries-parser-yaml": "^1.0.0", + "preliminaries": "1.1.0", + "preliminaries-parser-toml": "1.1.0", + "preliminaries-parser-yaml": "1.1.0", "prismjs": "^1.5.1", "prosemirror-commands": "^0.16.0", "prosemirror-history": "^0.16.0", diff --git a/yarn.lock b/yarn.lock index 2c215a4a..3faf1374 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2940,12 +2940,6 @@ express@^4.13.3: utils-merge "1.0.0" vary "~1.1.0" -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - dependencies: - is-extendable "^0.1.0" - extend@^3.0.0, extend@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" @@ -3880,7 +3874,7 @@ is-es2016-keyword@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-es2016-keyword/-/is-es2016-keyword-1.0.0.tgz#f6e54e110c5e4f8d265e69d2ed0eaf8cf5f47718" -is-extendable@^0.1.0, is-extendable@^0.1.1: +is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -6796,25 +6790,22 @@ pre-commit@^1.1.3: spawn-sync "^1.0.15" which "1.2.x" -preliminaries-parser-toml@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/preliminaries-parser-toml/-/preliminaries-parser-toml-1.0.1.tgz#009cadc4d801428a05eada48d8ec438a3f690a5f" +preliminaries-parser-toml@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/preliminaries-parser-toml/-/preliminaries-parser-toml-1.1.0.tgz#00cacf5ab619561380e0f6f2495b2ec449b8e70e" dependencies: toml "^2.3.2" toml-js "0.0.8" -preliminaries-parser-yaml@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/preliminaries-parser-yaml/-/preliminaries-parser-yaml-1.0.0.tgz#80da4ed54278fdf2f1e9ce379ab6cdce15cd7b54" +preliminaries-parser-yaml@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/preliminaries-parser-yaml/-/preliminaries-parser-yaml-1.1.0.tgz#cd0968d10e0220f55477cc8cbeb428aa27e9f84f" dependencies: - extend-shallow "^2.0.1" js-yaml "^3.8.1" -preliminaries@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/preliminaries/-/preliminaries-1.0.0.tgz#973aead5fbc2c8371bcba7de4413c3e8afe16cc1" - dependencies: - extend-shallow "^2.0.1" +preliminaries@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/preliminaries/-/preliminaries-1.1.0.tgz#28ceb5f988b83594de0a7b155124693b0c4a777f" prelude-ls@~1.1.2: version "1.1.2"