debian-mirror-gitlab/scripts/lib/glfm/render_wysiwyg_html_and_json.js
2022-07-16 19:58:13 +02:00

152 lines
5.9 KiB
JavaScript

import fs from 'fs';
import { DOMSerializer } from 'prosemirror-model';
import jsYaml from 'js-yaml';
// TODO: DRY up duplication with spec/frontend/content_editor/services/markdown_serializer_spec.js
// See https://gitlab.com/groups/gitlab-org/-/epics/7719#plan
import Blockquote from '~/content_editor/extensions/blockquote';
import Bold from '~/content_editor/extensions/bold';
import BulletList from '~/content_editor/extensions/bullet_list';
import Code from '~/content_editor/extensions/code';
import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
import DescriptionItem from '~/content_editor/extensions/description_item';
import DescriptionList from '~/content_editor/extensions/description_list';
import Details from '~/content_editor/extensions/details';
import DetailsContent from '~/content_editor/extensions/details_content';
import Division from '~/content_editor/extensions/division';
import Emoji from '~/content_editor/extensions/emoji';
import Figure from '~/content_editor/extensions/figure';
import FigureCaption from '~/content_editor/extensions/figure_caption';
import FootnoteDefinition from '~/content_editor/extensions/footnote_definition';
import FootnoteReference from '~/content_editor/extensions/footnote_reference';
import FootnotesSection from '~/content_editor/extensions/footnotes_section';
import HardBreak from '~/content_editor/extensions/hard_break';
import Heading from '~/content_editor/extensions/heading';
import HorizontalRule from '~/content_editor/extensions/horizontal_rule';
import Image from '~/content_editor/extensions/image';
import InlineDiff from '~/content_editor/extensions/inline_diff';
import Italic from '~/content_editor/extensions/italic';
import Link from '~/content_editor/extensions/link';
import ListItem from '~/content_editor/extensions/list_item';
import OrderedList from '~/content_editor/extensions/ordered_list';
import Strike from '~/content_editor/extensions/strike';
import Table from '~/content_editor/extensions/table';
import TableCell from '~/content_editor/extensions/table_cell';
import TableHeader from '~/content_editor/extensions/table_header';
import TableRow from '~/content_editor/extensions/table_row';
import TaskItem from '~/content_editor/extensions/task_item';
import TaskList from '~/content_editor/extensions/task_list';
import createMarkdownDeserializer from '~/content_editor/services/remark_markdown_deserializer';
import { createTestEditor } from 'jest/content_editor/test_utils';
import { setTestTimeout } from 'jest/__helpers__/timeout';
const tiptapEditor = createTestEditor({
extensions: [
Blockquote,
Bold,
BulletList,
Code,
CodeBlockHighlight,
DescriptionItem,
DescriptionList,
Details,
DetailsContent,
Division,
Emoji,
FootnoteDefinition,
FootnoteReference,
FootnotesSection,
Figure,
FigureCaption,
HardBreak,
Heading,
HorizontalRule,
Image,
InlineDiff,
Italic,
Link,
ListItem,
OrderedList,
Strike,
Table,
TableCell,
TableHeader,
TableRow,
TaskItem,
TaskList,
],
});
async function renderMarkdownToHTMLAndJSON(markdown, schema, deserializer) {
let prosemirrorDocument;
try {
const { document } = await deserializer.deserialize({ schema, content: markdown });
prosemirrorDocument = document;
} catch (e) {
const errorMsg = `Error - check implementation:\n${e.message}`;
return {
html: errorMsg,
json: errorMsg,
};
}
const documentFragment = DOMSerializer.fromSchema(schema).serializeFragment(
prosemirrorDocument.content,
);
const htmlString = documentFragment.firstChild.outerHTML;
const json = prosemirrorDocument.toJSON();
const jsonString = JSON.stringify(json, null, 2);
return { html: htmlString, json: jsonString };
}
function renderHtmlAndJsonForAllExamples(markdownExamples) {
const { schema } = tiptapEditor;
const deserializer = createMarkdownDeserializer();
const exampleNames = Object.keys(markdownExamples);
return exampleNames.reduce(async (promisedExamples, exampleName) => {
const markdown = markdownExamples[exampleName];
const htmlAndJson = await renderMarkdownToHTMLAndJSON(markdown, schema, deserializer);
const examples = await promisedExamples;
examples[exampleName] = htmlAndJson;
return examples;
}, Promise.resolve({}));
}
/* eslint-disable no-undef */
jest.mock('~/emoji');
// The purpose of this file is to deserialize markdown examples
// to WYSIWYG HTML and to prosemirror documents in JSON form, using
// the logic implemented as part of the Content Editor.
//
// It reads an input YAML file containing all the markdown examples,
// and outputs a YAML files containing the rendered HTML and JSON
// corresponding each markdown example.
//
// The input and output file paths are provides as command line arguments.
//
// Although it is implemented as a Jest test, it is not a unit test. We use
// Jest because that is the simplest environment in which to execute the
// relevant Content Editor logic.
//
//
// This script should be invoked via jest with the a command similar to the following:
// yarn jest --testMatch '**/render_wysiwyg_html_and_json.js' ./scripts/lib/glfm/render_wysiwyg_html_and_json.js
it('serializes html to prosemirror json', async () => {
setTestTimeout(20000);
const inputMarkdownTempfilePath = process.env.INPUT_MARKDOWN_YML_PATH;
expect(inputMarkdownTempfilePath).not.toBeUndefined();
const outputWysiwygHtmlAndJsonTempfilePath =
process.env.OUTPUT_WYSIWYG_HTML_AND_JSON_TEMPFILE_PATH;
expect(outputWysiwygHtmlAndJsonTempfilePath).not.toBeUndefined();
/* eslint-enable no-undef */
const markdownExamples = jsYaml.safeLoad(fs.readFileSync(inputMarkdownTempfilePath), {});
const htmlAndJsonExamples = await renderHtmlAndJsonForAllExamples(markdownExamples);
const htmlAndJsonExamplesYamlString = jsYaml.safeDump(htmlAndJsonExamples, {});
fs.writeFileSync(outputWysiwygHtmlAndJsonTempfilePath, htmlAndJsonExamplesYamlString);
});