Commit f230f853 authored by derek-knox's avatar derek-knox

Add toml and json front matter support to SSE

Additionally cleanup tests to differentiate
between yaml content and front matter (default),
toml, and json
parent 5cad762b
const parseSourceFile = raw => {
const frontMatterRegex = /(^---$[\s\S]*?^---$)/m;
const preGroupedRegex = /([\s\S]*?)(^---$[\s\S]*?^---$)(\s*)([\s\S]*)/m; // preFrontMatter, frontMatter, spacing, and content
import getFrontMatterLanguageDefinition from './parse_source_file_language_support';
const parseSourceFile = (raw, options = { frontMatterLanguage: 'yaml' }) => {
const { open, close } = getFrontMatterLanguageDefinition(options.frontMatterLanguage);
const anyChar = '[\\s\\S]';
const frontMatterBlock = `^${open}$${anyChar}*?^${close}$`;
const frontMatterRegex = new RegExp(`${frontMatterBlock}`, 'm');
const preGroupedRegex = new RegExp(`(${anyChar}*?)(${frontMatterBlock})(\\s*)(${anyChar}*)`, 'm'); // preFrontMatter, frontMatter, spacing, and content
let initial;
let editable;
......
const frontMatterLanguageDefinitions = [
{ name: 'yaml', open: '---', close: '---' },
{ name: 'toml', open: '\\+\\+\\+', close: '\\+\\+\\+' },
{ name: 'json', open: '{', close: '}' },
];
const getFrontMatterLanguageDefinition = name => {
const languageDefinition = frontMatterLanguageDefinitions.find(def => def.name === name);
if (!languageDefinition) {
throw new Error(`Unsupported front matter language: ${name}`);
}
return languageDefinition;
};
export default getFrontMatterLanguageDefinition;
---
title: Add toml and json front matter language support to Static Site Editor's WYSIWYG mode
merge_request: 40718
author:
type: added
......@@ -10,7 +10,7 @@ import UnsavedChangesConfirmDialog from '~/static_site_editor/components/unsaved
import {
sourceContentTitle as title,
sourceContent as content,
sourceContentYAML as content,
sourceContentBody as body,
returnUrl,
} from '../mock_data';
......
......@@ -5,7 +5,7 @@ import {
projectId,
sourcePath,
sourceContentTitle as title,
sourceContent as content,
sourceContentYAML as content,
} from '../../mock_data';
jest.mock('~/static_site_editor/services/load_source_content', () => jest.fn());
......
......@@ -6,7 +6,7 @@ import {
projectId as project,
sourcePath,
username,
sourceContent as content,
sourceContentYAML as content,
savedContentMeta,
} from '../../mock_data';
......
export const sourceContentHeader = `---
export const sourceContentHeaderYAML = `---
layout: handbook-page-toc
title: Handbook
twitter_image: '/images/tweets/handbook-gitlab.png'
---`;
export const sourceContentHeaderTOML = `+++
layout: "handbook-page-toc"
title: "Handbook"
twitter_image: "/images/tweets/handbook-gitlab.png"
+++`;
export const sourceContentHeaderJSON = `{
"layout": "handbook-page-toc",
"title": "Handbook",
"twitter_image": "/images/tweets/handbook-gitlab.png",
}`;
export const sourceContentSpacing = `
`;
export const sourceContentBody = `## On this page
......@@ -13,7 +23,9 @@ export const sourceContentBody = `## On this page
![image](path/to/image1.png)
`;
export const sourceContent = `${sourceContentHeader}${sourceContentSpacing}${sourceContentBody}`;
export const sourceContentYAML = `${sourceContentHeaderYAML}${sourceContentSpacing}${sourceContentBody}`;
export const sourceContentTOML = `${sourceContentHeaderTOML}${sourceContentSpacing}${sourceContentBody}`;
export const sourceContentJSON = `${sourceContentHeaderJSON}${sourceContentSpacing}${sourceContentBody}`;
export const sourceContentTitle = 'Handbook';
export const username = 'gitlabuser';
......
......@@ -13,7 +13,7 @@ import { TRACKING_ACTION_INITIALIZE_EDITOR } from '~/static_site_editor/constant
import {
projectId as project,
returnUrl,
sourceContent as content,
sourceContentYAML as content,
sourceContentTitle as title,
sourcePath,
username,
......
......@@ -2,7 +2,12 @@ import Api from '~/api';
import loadSourceContent from '~/static_site_editor/services/load_source_content';
import { sourceContent, sourceContentTitle, projectId, sourcePath } from '../mock_data';
import {
sourceContentYAML as sourceContent,
sourceContentTitle,
projectId,
sourcePath,
} from '../mock_data';
describe('loadSourceContent', () => {
describe('requesting source content succeeds', () => {
......
import getFrontMatterLanguageDefinition from '~/static_site_editor/services/parse_source_file_language_support';
describe('static_site_editor/services/parse_source_file_language_support', () => {
describe('getFrontMatterLanguageDefinition', () => {
it.each`
languageName
${'yaml'}
${'toml'}
${'json'}
${'abcd'}
`('returns $hasMatch when provided $languageName', ({ languageName }) => {
try {
const definition = getFrontMatterLanguageDefinition(languageName);
expect(definition.name).toBe(languageName);
} catch (error) {
expect(error.message).toBe(`Unsupported front matter language: ${languageName}`);
}
});
});
});
import {
sourceContent as content,
sourceContentHeader as frontMatter,
sourceContentYAML as content,
sourceContentTOML as tomlContent,
sourceContentJSON as jsonContent,
sourceContentHeaderYAML as yamlFrontMatter,
sourceContentHeaderTOML as tomlFrontMatter,
sourceContentHeaderJSON as jsonFrontMatter,
sourceContentBody as body,
} from '../mock_data';
import parseSourceFile from '~/static_site_editor/services/parse_source_file';
describe('parseSourceFile', () => {
describe('static_site_editor/services/parse_source_file', () => {
const contentComplex = [content, content, content].join('');
const complexBody = [body, content, content].join('');
const edit = 'and more';
......@@ -14,13 +18,22 @@ describe('parseSourceFile', () => {
const newContentComplex = `${contentComplex} ${edit}`;
describe('unmodified front matter', () => {
const yamlOptions = { frontMatterLanguage: 'yaml' };
it.each`
parsedSource
${parseSourceFile(content)}
${parseSourceFile(contentComplex)}
`('returns the correct front matter when queried', ({ parsedSource }) => {
expect(parsedSource.frontMatter()).toBe(frontMatter);
});
parsedSource | targetFrontMatter
${parseSourceFile(content)} | ${yamlFrontMatter}
${parseSourceFile(contentComplex)} | ${yamlFrontMatter}
${parseSourceFile(content, yamlOptions)} | ${yamlFrontMatter}
${parseSourceFile(contentComplex, yamlOptions)} | ${yamlFrontMatter}
${parseSourceFile(tomlContent, { frontMatterLanguage: 'toml' })} | ${tomlFrontMatter}
${parseSourceFile(jsonContent, { frontMatterLanguage: 'json' })} | ${jsonFrontMatter}
`(
'returns $targetFrontMatter when frontMatter queried',
({ parsedSource, targetFrontMatter }) => {
expect(parsedSource.frontMatter()).toBe(targetFrontMatter);
},
);
});
describe('unmodified content', () => {
......@@ -49,9 +62,12 @@ describe('parseSourceFile', () => {
});
describe('modified front matter', () => {
const newFrontMatter = '---\nnewKey: newVal\n---';
const contentWithNewFrontMatter = content.replace(frontMatter, newFrontMatter);
const contentComplexWithNewFrontMatter = contentComplex.replace(frontMatter, newFrontMatter);
const newYamlFrontMatter = '---\nnewKey: newVal\n---';
const contentWithNewFrontMatter = content.replace(yamlFrontMatter, newYamlFrontMatter);
const contentComplexWithNewFrontMatter = contentComplex.replace(
yamlFrontMatter,
newYamlFrontMatter,
);
it.each`
parsedSource | targetContent
......@@ -60,11 +76,11 @@ describe('parseSourceFile', () => {
`(
'returns the correct front matter and modified content',
({ parsedSource, targetContent }) => {
expect(parsedSource.frontMatter()).toBe(frontMatter);
expect(parsedSource.frontMatter()).toBe(yamlFrontMatter);
parsedSource.setFrontMatter(newFrontMatter);
parsedSource.setFrontMatter(newYamlFrontMatter);
expect(parsedSource.frontMatter()).toBe(newFrontMatter);
expect(parsedSource.frontMatter()).toBe(newYamlFrontMatter);
expect(parsedSource.content()).toBe(targetContent);
},
);
......
......@@ -20,7 +20,7 @@ import {
commitMultipleResponse,
createMergeRequestResponse,
sourcePath,
sourceContent as content,
sourceContentYAML as content,
trackingCategory,
images,
} from '../mock_data';
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment