Cleanup file formatters. (#759)

* Clean up frontmatter formatter.

* Move `formatToExtension`.

* Use plain objects for file formatters.

* Use same parsers for files and frontmatter.

We want to use our file parsers for frontmatter, instead of the builtin
ones, as they process some formats (images, dates) properly.

* Cleanup YAML frontmatter parser code.
This commit is contained in:
Caleb 2017-10-30 13:48:19 -06:00 committed by Benaiah Mischenko
parent 2c19c221e7
commit 1bb2b56366
7 changed files with 38 additions and 52 deletions

View File

@ -1,9 +1,7 @@
import Frontmatter from '../frontmatter'; import FrontmatterFormatter from '../frontmatter';
jest.mock("../../valueObjects/AssetProxy.js"); jest.mock("../../valueObjects/AssetProxy.js");
const FrontmatterFormatter = new Frontmatter();
describe('Frontmatter', () => { describe('Frontmatter', () => {
it('should parse YAML with --- delimiters', () => { it('should parse YAML with --- delimiters', () => {
expect( expect(

View File

@ -1,12 +1,15 @@
import YAML from './yaml'; import yamlFormatter from './yaml';
import TOML from './toml'; import tomlFormatter from './toml';
import JSONFormatter from './json'; import jsonFormatter from './json';
import Frontmatter from './frontmatter'; import FrontmatterFormatter from './frontmatter';
const yamlFormatter = new YAML(); export const formatToExtension = format => ({
const tomlFormatter = new TOML(); markdown: 'md',
const jsonFormatter = new JSONFormatter(); yaml: 'yml',
const FrontmatterFormatter = new Frontmatter(); toml: 'toml',
json: 'json',
html: 'html',
}[format]);
function formatByType(type) { function formatByType(type) {
// Right now the only type is "editorialWorkflow" and // Right now the only type is "editorialWorkflow" and

View File

@ -1,12 +1,11 @@
import matter from 'gray-matter'; import matter from 'gray-matter';
import TOML from './toml'; import tomlFormatter from './toml';
import YAML from './yaml'; import yamlFormatter from './yaml';
import jsonFormatter from './json';
const tomlFormatter = new TOML();
const parsers = { const parsers = {
toml: tomlFormatter.fromFile.bind(tomlFormatter), toml: input => tomlFormatter.fromFile(input),
json: (input) => { json: input => {
let JSONinput = input.trim(); let JSONinput = input.trim();
// Fix JSON if leading and trailing brackets were trimmed. // Fix JSON if leading and trailing brackets were trimmed.
if (JSONinput.substr(0, 1) !== '{') { if (JSONinput.substr(0, 1) !== '{') {
@ -15,7 +14,11 @@ const parsers = {
if (JSONinput.substr(-1) !== '}') { if (JSONinput.substr(-1) !== '}') {
JSONinput = JSONinput + '}'; JSONinput = JSONinput + '}';
} }
return matter.engines.json.parse(JSONinput); return jsonFormatter.fromFile(JSONinput);
},
yaml: {
parse: input => yamlFormatter.fromFile(input),
stringify: (metadata, { sortedKeys }) => yamlFormatter.toFile(metadata, sortedKeys),
}, },
} }
@ -37,31 +40,20 @@ function inferFrontmatterFormat(str) {
} }
} }
export default class Frontmatter { export default {
fromFile(content) { fromFile(content) {
const result = matter(content, { engines: parsers, ...inferFrontmatterFormat(content) }); const result = matter(content, { engines: parsers, ...inferFrontmatterFormat(content) });
const data = result.data; return {
data.body = result.content; ...result.data,
return data; body: result.content,
} };
},
toFile(data, sortedKeys) { toFile(data, sortedKeys) {
const meta = {}; const { body, ...meta } = data;
let body = '';
Object.keys(data).forEach((key) => {
if (key === 'body') {
body = data[key];
} else {
meta[key] = data[key];
}
});
// always stringify to YAML // always stringify to YAML
const parser = { // `sortedKeys` is not recognized by gray-matter, so it gets passed through to the parser
stringify(metadata) { return matter.stringify(body, meta, { engines: parsers, language: "yaml", delimiters: "---", sortedKeys });
return new YAML().toFile(metadata, sortedKeys);
},
};
return matter.stringify(body, meta, { language: "yaml", delimiters: "---", engines: { yaml: parser } });
} }
} }

View File

@ -1,7 +1,7 @@
export default class JSONFormatter { export default {
fromFile(content) { fromFile(content) {
return JSON.parse(content); return JSON.parse(content);
} },
toFile(data) { toFile(data) {
return JSON.stringify(data); return JSON.stringify(data);

View File

@ -15,10 +15,10 @@ const outputReplacer = (key, value) => {
return false; return false;
}; };
export default class TOML { export default {
fromFile(content) { fromFile(content) {
return toml.parse(content); return toml.parse(content);
} },
toFile(data, sortedKeys = []) { toFile(data, sortedKeys = []) {
return tomlify.toToml(data, { replace: outputReplacer, sort: sortKeys(sortedKeys) }); return tomlify.toToml(data, { replace: outputReplacer, sort: sortKeys(sortedKeys) });

View File

@ -36,10 +36,10 @@ const OutputSchema = new yaml.Schema({
explicit: yaml.DEFAULT_SAFE_SCHEMA.explicit, explicit: yaml.DEFAULT_SAFE_SCHEMA.explicit,
}); });
export default class YAML { export default {
fromFile(content) { fromFile(content) {
return yaml.safeLoad(content); return yaml.safeLoad(content);
} },
toFile(data, sortedKeys = []) { toFile(data, sortedKeys = []) {
return yaml.safeDump(data, { schema: OutputSchema, sortKeys: sortKeys(sortedKeys) }); return yaml.safeDump(data, { schema: OutputSchema, sortKeys: sortKeys(sortedKeys) });

View File

@ -4,6 +4,7 @@ import consoleError from '../lib/consoleError';
import { CONFIG_SUCCESS } from '../actions/config'; import { CONFIG_SUCCESS } from '../actions/config';
import { FILES, FOLDER } from '../constants/collectionTypes'; import { FILES, FOLDER } from '../constants/collectionTypes';
import { INFERABLE_FIELDS } from '../constants/fieldInference'; import { INFERABLE_FIELDS } from '../constants/fieldInference';
import { formatToExtension } from '../formats/formats';
const collections = (state = null, action) => { const collections = (state = null, action) => {
const configCollections = action.payload && action.payload.collections; const configCollections = action.payload && action.payload.collections;
@ -26,14 +27,6 @@ const collections = (state = null, action) => {
} }
}; };
const formatToExtension = format => ({
markdown: 'md',
yaml: 'yml',
toml: 'toml',
json: 'json',
html: 'html',
}[format]);
const selectors = { const selectors = {
[FOLDER]: { [FOLDER]: {
entryExtension(collection) { entryExtension(collection) {