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 => { import getFrontMatterLanguageDefinition from './parse_source_file_language_support';
const frontMatterRegex = /(^---$[\s\S]*?^---$)/m;
const preGroupedRegex = /([\s\S]*?)(^---$[\s\S]*?^---$)(\s*)([\s\S]*)/m; // preFrontMatter, frontMatter, spacing, and content 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 initial;
let editable; 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 ...@@ -10,7 +10,7 @@ import UnsavedChangesConfirmDialog from '~/static_site_editor/components/unsaved
import { import {
sourceContentTitle as title, sourceContentTitle as title,
sourceContent as content, sourceContentYAML as content,
sourceContentBody as body, sourceContentBody as body,
returnUrl, returnUrl,
} from '../mock_data'; } from '../mock_data';
......
...@@ -5,7 +5,7 @@ import { ...@@ -5,7 +5,7 @@ import {
projectId, projectId,
sourcePath, sourcePath,
sourceContentTitle as title, sourceContentTitle as title,
sourceContent as content, sourceContentYAML as content,
} from '../../mock_data'; } from '../../mock_data';
jest.mock('~/static_site_editor/services/load_source_content', () => jest.fn()); jest.mock('~/static_site_editor/services/load_source_content', () => jest.fn());
......
...@@ -6,7 +6,7 @@ import { ...@@ -6,7 +6,7 @@ import {
projectId as project, projectId as project,
sourcePath, sourcePath,
username, username,
sourceContent as content, sourceContentYAML as content,
savedContentMeta, savedContentMeta,
} from '../../mock_data'; } from '../../mock_data';
......
export const sourceContentHeader = `--- export const sourceContentHeaderYAML = `---
layout: handbook-page-toc layout: handbook-page-toc
title: Handbook title: Handbook
twitter_image: '/images/tweets/handbook-gitlab.png' 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 sourceContentSpacing = `
`; `;
export const sourceContentBody = `## On this page export const sourceContentBody = `## On this page
...@@ -13,7 +23,9 @@ export const sourceContentBody = `## On this page ...@@ -13,7 +23,9 @@ export const sourceContentBody = `## On this page
![image](path/to/image1.png) ![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 sourceContentTitle = 'Handbook';
export const username = 'gitlabuser'; export const username = 'gitlabuser';
......
...@@ -13,7 +13,7 @@ import { TRACKING_ACTION_INITIALIZE_EDITOR } from '~/static_site_editor/constant ...@@ -13,7 +13,7 @@ import { TRACKING_ACTION_INITIALIZE_EDITOR } from '~/static_site_editor/constant
import { import {
projectId as project, projectId as project,
returnUrl, returnUrl,
sourceContent as content, sourceContentYAML as content,
sourceContentTitle as title, sourceContentTitle as title,
sourcePath, sourcePath,
username, username,
......
...@@ -2,7 +2,12 @@ import Api from '~/api'; ...@@ -2,7 +2,12 @@ import Api from '~/api';
import loadSourceContent from '~/static_site_editor/services/load_source_content'; 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('loadSourceContent', () => {
describe('requesting source content succeeds', () => { 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 { import {
sourceContent as content, sourceContentYAML as content,
sourceContentHeader as frontMatter, sourceContentTOML as tomlContent,
sourceContentJSON as jsonContent,
sourceContentHeaderYAML as yamlFrontMatter,
sourceContentHeaderTOML as tomlFrontMatter,
sourceContentHeaderJSON as jsonFrontMatter,
sourceContentBody as body, sourceContentBody as body,
} from '../mock_data'; } from '../mock_data';
import parseSourceFile from '~/static_site_editor/services/parse_source_file'; 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 contentComplex = [content, content, content].join('');
const complexBody = [body, content, content].join(''); const complexBody = [body, content, content].join('');
const edit = 'and more'; const edit = 'and more';
...@@ -14,13 +18,22 @@ describe('parseSourceFile', () => { ...@@ -14,13 +18,22 @@ describe('parseSourceFile', () => {
const newContentComplex = `${contentComplex} ${edit}`; const newContentComplex = `${contentComplex} ${edit}`;
describe('unmodified front matter', () => { describe('unmodified front matter', () => {
const yamlOptions = { frontMatterLanguage: 'yaml' };
it.each` it.each`
parsedSource parsedSource | targetFrontMatter
${parseSourceFile(content)} ${parseSourceFile(content)} | ${yamlFrontMatter}
${parseSourceFile(contentComplex)} ${parseSourceFile(contentComplex)} | ${yamlFrontMatter}
`('returns the correct front matter when queried', ({ parsedSource }) => { ${parseSourceFile(content, yamlOptions)} | ${yamlFrontMatter}
expect(parsedSource.frontMatter()).toBe(frontMatter); ${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', () => { describe('unmodified content', () => {
...@@ -49,9 +62,12 @@ describe('parseSourceFile', () => { ...@@ -49,9 +62,12 @@ describe('parseSourceFile', () => {
}); });
describe('modified front matter', () => { describe('modified front matter', () => {
const newFrontMatter = '---\nnewKey: newVal\n---'; const newYamlFrontMatter = '---\nnewKey: newVal\n---';
const contentWithNewFrontMatter = content.replace(frontMatter, newFrontMatter); const contentWithNewFrontMatter = content.replace(yamlFrontMatter, newYamlFrontMatter);
const contentComplexWithNewFrontMatter = contentComplex.replace(frontMatter, newFrontMatter); const contentComplexWithNewFrontMatter = contentComplex.replace(
yamlFrontMatter,
newYamlFrontMatter,
);
it.each` it.each`
parsedSource | targetContent parsedSource | targetContent
...@@ -60,11 +76,11 @@ describe('parseSourceFile', () => { ...@@ -60,11 +76,11 @@ describe('parseSourceFile', () => {
`( `(
'returns the correct front matter and modified content', 'returns the correct front matter and modified content',
({ parsedSource, targetContent }) => { ({ 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); expect(parsedSource.content()).toBe(targetContent);
}, },
); );
......
...@@ -20,7 +20,7 @@ import { ...@@ -20,7 +20,7 @@ import {
commitMultipleResponse, commitMultipleResponse,
createMergeRequestResponse, createMergeRequestResponse,
sourcePath, sourcePath,
sourceContent as content, sourceContentYAML as content,
trackingCategory, trackingCategory,
images, images,
} from '../mock_data'; } 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