chore: add code formatting and linting (#952)

This commit is contained in:
Caleb
2018-08-07 14:46:54 -06:00
committed by Shawn Erquhart
parent 32e0a9b2b5
commit f801b19221
265 changed files with 5988 additions and 4481 deletions

View File

@ -99,5 +99,5 @@ RawEditor.propTypes = {
onMode: PropTypes.func.isRequired,
className: PropTypes.string.isRequired,
value: PropTypes.string,
field: ImmutablePropTypes.map
field: ImmutablePropTypes.map,
};

View File

@ -12,22 +12,24 @@ const ShortcodeContainer = styled.div`
margin: 12px 0;
padding: 14px;
${props => props.collapsed && css`
background-color: ${colors.textFieldBorder};
cursor: pointer;
`}
`
${props =>
props.collapsed &&
css`
background-color: ${colors.textFieldBorder};
cursor: pointer;
`};
`;
const ShortcodeTopBar = styled(ListItemTopBar)`
background-color: ${colors.textFieldBorder};
margin: -14px -14px 0;
border-radius: 0;
`
`;
const ShortcodeTitle = styled.div`
padding: 8px;
color: ${colors.controlLabel};
`
`;
export default class Shortcode extends React.Component {
constructor(props) {
@ -51,16 +53,14 @@ export default class Shortcode extends React.Component {
handleCollapseToggle = () => {
this.setState({ collapsed: !this.state.collapsed });
}
};
handleRemove = () => {
const { editor, node } = this.props;
editor.change(change => {
change
.removeNodeByKey(node.key)
.focus();
change.removeNodeByKey(node.key).focus();
});
}
};
handleClick = event => {
/**
@ -75,18 +75,18 @@ export default class Shortcode extends React.Component {
if (this.state.collapsed) {
this.handleCollapseToggle();
}
}
};
renderControl = (shortcodeData, field) => {
if (field.get('widget') === 'hidden') return null;
const value = shortcodeData.get(field.get('name'));
const key = `field-${ field.get('name') }`;
const key = `field-${field.get('name')}`;
const Control = getEditorControl();
const controlProps = { field, value, onChange: this.handleChange };
return (
<div key={key}>
<Control {...controlProps}/>
<Control {...controlProps} />
</div>
);
};
@ -104,11 +104,11 @@ export default class Shortcode extends React.Component {
onCollapseToggle={this.handleCollapseToggle}
onRemove={this.handleRemove}
/>
{
collapsed
? <ShortcodeTitle>{capitalize(pluginId)}</ShortcodeTitle>
: plugin.get('fields').map(partial(this.renderControl, shortcodeData))
}
{collapsed ? (
<ShortcodeTitle>{capitalize(pluginId)}</ShortcodeTitle>
) : (
plugin.get('fields').map(partial(this.renderControl, shortcodeData))
)}
</ShortcodeContainer>
);
}

View File

@ -27,7 +27,7 @@ const ToolbarContainer = styled.div`
const ToolbarDropdownWrapper = styled.div`
display: inline-block;
position: relative;
`
`;
const ToolbarToggle = styled.div`
flex-shrink: 0;
@ -35,7 +35,7 @@ const ToolbarToggle = styled.div`
align-items: center;
font-size: 14px;
margin: 0 10px;
`
`;
const StyledToggle = ToolbarToggle.withComponent(Toggle);
@ -44,13 +44,15 @@ const ToolbarToggleLabel = styled.span`
text-align: center;
white-space: nowrap;
line-height: 20px;
width: ${props => props.offPosition ? '62px' : '70px'};
width: ${props => (props.offPosition ? '62px' : '70px')};
${props => props.isActive && css`
font-weight: 600;
color: ${colors.active};
`}
`
${props =>
props.isActive &&
css`
font-weight: 600;
color: ${colors.active};
`};
`;
export default class Toolbar extends React.Component {
static propTypes = {
@ -67,7 +69,7 @@ export default class Toolbar extends React.Component {
isHidden = button => {
const { buttons } = this.props;
return List.isList(buttons) ? !buttons.includes(button) : false;
}
};
render() {
const {
@ -191,15 +193,24 @@ export default class Toolbar extends React.Component {
</DropdownButton>
)}
>
{plugins && plugins.toList().map((plugin, idx) => (
<DropdownItem key={idx} label={plugin.get('label')} onClick={() => onSubmit(plugin.get('id'))} />
))}
{plugins &&
plugins
.toList()
.map((plugin, idx) => (
<DropdownItem
key={idx}
label={plugin.get('label')}
onClick={() => onSubmit(plugin.get('id'))}
/>
))}
</Dropdown>
</ToolbarDropdownWrapper>
</div>
<ToolbarToggle>
<ToolbarToggleLabel isActive={!rawMode} offPosition>Rich Text</ToolbarToggleLabel>
<StyledToggle active={rawMode} onChange={onToggleMode}/>
<ToolbarToggleLabel isActive={!rawMode} offPosition>
Rich Text
</ToolbarToggleLabel>
<StyledToggle active={rawMode} onChange={onToggleMode} />
<ToolbarToggleLabel isActive={rawMode}>Markdown</ToolbarToggleLabel>
</ToolbarToggle>
</ToolbarContainer>

View File

@ -10,7 +10,7 @@ const StyledToolbarButton = styled.button`
border: none;
background-color: transparent;
font-size: 16px;
color: ${props => props.isActive ? '#1e2532' : 'inherit'};
color: ${props => (props.isActive ? '#1e2532' : 'inherit')};
cursor: pointer;
&:disabled {
@ -21,7 +21,7 @@ const StyledToolbarButton = styled.button`
${Icon} {
display: block;
}
`
`;
const ToolbarButton = ({ type, label, icon, onClick, isActive, isHidden, disabled }) => {
if (isHidden) {
@ -35,7 +35,7 @@ const ToolbarButton = ({ type, label, icon, onClick, isActive, isHidden, disable
title={label}
disabled={disabled}
>
{ icon ? <Icon type={icon}/> : label }
{icon ? <Icon type={icon} /> : label}
</StyledToolbarButton>
);
};

View File

@ -17,20 +17,20 @@ import { EditorControlBar } from '../styles';
const VisualEditorContainer = styled.div`
position: relative;
`
`;
const createEmptyRawDoc = () => {
const emptyText = Text.create('');
const emptyBlock = Block.create({ kind: 'block', type: 'paragraph', nodes: [ emptyText ] });
const emptyBlock = Block.create({ kind: 'block', type: 'paragraph', nodes: [emptyText] });
return { nodes: [emptyBlock] };
};
const createSlateValue = (rawValue) => {
const createSlateValue = rawValue => {
const rawDoc = rawValue && markdownToSlate(rawValue);
const rawDocHasNodes = !isEmpty(get(rawDoc, 'nodes'))
const rawDocHasNodes = !isEmpty(get(rawDoc, 'nodes'));
const document = Document.fromJSON(rawDocHasNodes ? rawDoc : createEmptyRawDoc());
return Value.create({ document });
}
};
export default class Editor extends React.Component {
static propTypes = {
@ -40,7 +40,7 @@ export default class Editor extends React.Component {
onMode: PropTypes.func.isRequired,
className: PropTypes.string.isRequired,
value: PropTypes.string,
field: ImmutablePropTypes.map
field: ImmutablePropTypes.map,
};
constructor(props) {
@ -61,14 +61,17 @@ export default class Editor extends React.Component {
const ast = htmlToSlate(data.html);
const doc = Document.fromJSON(ast);
return change.insertFragment(doc);
}
};
selectionHasMark = type => this.state.value.activeMarks.some(mark => mark.type === type);
selectionHasBlock = type => this.state.value.blocks.some(node => node.type === type);
handleMarkClick = (event, type) => {
event.preventDefault();
const resolvedChange = this.state.value.change().focus().toggleMark(type);
const resolvedChange = this.state.value
.change()
.focus()
.toggleMark(type);
this.ref.onChange(resolvedChange);
this.setState({ value: resolvedChange.value });
};
@ -119,9 +122,7 @@ export default class Editor extends React.Component {
// should simply unlink them.
if (this.hasLinks()) {
change = change.unwrapInline('link');
}
else {
} else {
const url = window.prompt('Enter the URL of the link');
// If nothing is entered in the URL prompt, do nothing.
@ -129,14 +130,10 @@ export default class Editor extends React.Component {
// If no text is selected, use the entered URL as text.
if (change.value.isCollapsed) {
change = change
.insertText(url)
.extend(0 - url.length);
change = change.insertText(url).extend(0 - url.length);
}
change = change
.wrapInline({ type: 'link', data: { url } })
.collapseToEnd();
change = change.wrapInline({ type: 'link', data: { url } }).collapseToEnd();
}
this.ref.onChange(change);
@ -155,7 +152,7 @@ export default class Editor extends React.Component {
shortcodeData: Map(),
},
isVoid: true,
nodes
nodes,
};
let change = value.change();
const { focusBlock } = change.value;
@ -176,7 +173,6 @@ export default class Editor extends React.Component {
this.props.onMode('raw');
};
handleDocumentChange = debounce(change => {
const { onChange } = this.props;
const raw = change.value.document.toJSON();
@ -193,7 +189,7 @@ export default class Editor extends React.Component {
processRef = ref => {
this.ref = ref;
}
};
render() {
const { onAddAsset, getAsset, className, field, getEditorComponents } = this.props;

View File

@ -2,8 +2,8 @@ import { markdownToSlate } from '../../serializers';
const parser = markdownToSlate;
describe("Compile markdown to Slate Raw AST", () => {
it("should compile simple markdown", () => {
describe('Compile markdown to Slate Raw AST', () => {
it('should compile simple markdown', () => {
const value = `
# H1
@ -12,7 +12,7 @@ sweet body
expect(parser(value)).toMatchSnapshot();
});
it("should compile a markdown ordered list", () => {
it('should compile a markdown ordered list', () => {
const value = `
# H1
@ -23,7 +23,7 @@ sweet body
expect(parser(value)).toMatchSnapshot();
});
it("should compile bulleted lists", () => {
it('should compile bulleted lists', () => {
const value = `
# H1
@ -34,7 +34,7 @@ sweet body
expect(parser(value)).toMatchSnapshot();
});
it("should compile multiple header levels", () => {
it('should compile multiple header levels', () => {
const value = `
# H1
@ -45,7 +45,7 @@ sweet body
expect(parser(value)).toMatchSnapshot();
});
it("should compile horizontal rules", () => {
it('should compile horizontal rules', () => {
const value = `
# H1
@ -56,7 +56,7 @@ blue moon
expect(parser(value)).toMatchSnapshot();
});
it("should compile horizontal rules", () => {
it('should compile horizontal rules', () => {
const value = `
# H1
@ -67,7 +67,7 @@ blue moon
expect(parser(value)).toMatchSnapshot();
});
it("should compile soft breaks (double space)", () => {
it('should compile soft breaks (double space)', () => {
const value = `
blue moon
footballs
@ -75,14 +75,14 @@ footballs
expect(parser(value)).toMatchSnapshot();
});
it("should compile images", () => {
it('should compile images', () => {
const value = `
![super](duper.jpg)
`;
expect(parser(value)).toMatchSnapshot();
});
it("should compile code blocks", () => {
it('should compile code blocks', () => {
const value = `
\`\`\`javascript
var a = 1;
@ -91,7 +91,7 @@ var a = 1;
expect(parser(value)).toMatchSnapshot();
});
it("should compile nested inline markup", () => {
it('should compile nested inline markup', () => {
const value = `
# Word
@ -102,7 +102,7 @@ perhaps **scalding** even
expect(parser(value)).toMatchSnapshot();
});
it("should compile inline code", () => {
it('should compile inline code', () => {
const value = `
# Word
@ -111,7 +111,7 @@ This is some sweet \`inline code\` yo!
expect(parser(value)).toMatchSnapshot();
});
it("should compile links", () => {
it('should compile links', () => {
const value = `
# Word
@ -120,7 +120,7 @@ How far is it to [Google](https://google.com) land?
expect(parser(value)).toMatchSnapshot();
});
it("should compile plugins", () => {
it('should compile plugins', () => {
const value = `
![test](test.png)
@ -129,7 +129,7 @@ How far is it to [Google](https://google.com) land?
expect(parser(value)).toMatchSnapshot();
});
it("should compile kitchen sink example", () => {
it('should compile kitchen sink example', () => {
const value = `
# An exhibit of Markdown

View File

@ -32,12 +32,12 @@ export default class MarkdownControl extends React.Component {
this.state = { mode: localStorage.getItem(MODE_STORAGE_KEY) || 'visual' };
}
handleMode = (mode) => {
handleMode = mode => {
this.setState({ mode });
localStorage.setItem(MODE_STORAGE_KEY, mode);
};
processRef = ref => this.ref = ref;
processRef = ref => (this.ref = ref);
render() {
const {

View File

@ -38,14 +38,9 @@ function onKeyDown(event, change) {
.collapseToStartOf(newBlock);
}
const marks = [
[ 'b', 'bold' ],
[ 'i', 'italic' ],
[ 's', 'strikethrough' ],
[ '`', 'code' ],
];
const marks = [['b', 'bold'], ['i', 'italic'], ['s', 'strikethrough'], ['`', 'code']];
const [ , markName ] = marks.find(([ key ]) => isHotkey(`mod+${key}`, event)) || [];
const [, markName] = marks.find(([key]) => isHotkey(`mod+${key}`, event)) || [];
if (markName) {
event.preventDefault();

View File

@ -15,18 +15,16 @@ const SoftBreak = (options = {}) => ({
const shouldClose = text.endsWith('\n');
if (shouldClose) {
return change
.deleteBackward(1)
.insertBlock(defaultBlock);
return change.deleteBackward(1).insertBlock(defaultBlock);
}
const textNode = Text.create('\n');
const breakNode = Inline.create({ type: 'break', nodes: [ textNode ] });
const breakNode = Inline.create({ type: 'break', nodes: [textNode] });
return change
.insertInline(breakNode)
.insertText('')
.collapseToStartOfNextText();
}
},
});
const SoftBreakOpts = {
@ -44,11 +42,18 @@ const BreakToDefaultBlock = ({ onlyIn = [], defaultBlock = 'paragraph' }) => ({
if (onlyIn.includes(value.startBlock.type)) {
return change.insertBlock(defaultBlock);
}
}
},
});
const BreakToDefaultBlockOpts = {
onlyIn: ['heading-one', 'heading-two', 'heading-three', 'heading-four', 'heading-five', 'heading-six'],
onlyIn: [
'heading-one',
'heading-two',
'heading-three',
'heading-four',
'heading-five',
'heading-six',
],
};
export const BreakToDefaultBlockConfigured = BreakToDefaultBlock(BreakToDefaultBlockOpts);
@ -67,7 +72,7 @@ const BackspaceCloseBlock = (options = {}) => ({
if (startBlock.text === '') {
return change.setBlock(defaultBlock).focus();
}
}
},
});
const BackspaceCloseBlockOpts = {

View File

@ -21,30 +21,46 @@ const Code = props => <code>{props.children}</code>;
const Paragraph = props => <p {...props.attributes}>{props.children}</p>;
const ListItem = props => <li {...props.attributes}>{props.children}</li>;
const Quote = props => <blockquote {...props.attributes}>{props.children}</blockquote>;
const CodeBlock = props => <pre><code {...props.attributes}>{props.children}</code></pre>;
const CodeBlock = props => (
<pre>
<code {...props.attributes}>{props.children}</code>
</pre>
);
const HeadingOne = props => <h1 {...props.attributes}>{props.children}</h1>;
const HeadingTwo = props => <h2 {...props.attributes}>{props.children}</h2>;
const HeadingThree = props => <h3 {...props.attributes}>{props.children}</h3>;
const HeadingFour = props => <h4 {...props.attributes}>{props.children}</h4>;
const HeadingFive = props => <h5 {...props.attributes}>{props.children}</h5>;
const HeadingSix = props => <h6 {...props.attributes}>{props.children}</h6>;
const Table = props => <table><tbody {...props.attributes}>{props.children}</tbody></table>;
const Table = props => (
<table>
<tbody {...props.attributes}>{props.children}</tbody>
</table>
);
const TableRow = props => <tr {...props.attributes}>{props.children}</tr>;
const TableCell = props => <td {...props.attributes}>{props.children}</td>;
const ThematicBreak = props => <hr {...props.attributes}/>;
const ThematicBreak = props => <hr {...props.attributes} />;
const BulletedList = props => <ul {...props.attributes}>{props.children}</ul>;
const NumberedList = props => (
<ol {...props.attributes} start={props.node.data.get('start') || 1}>{props.children}</ol>
<ol {...props.attributes} start={props.node.data.get('start') || 1}>
{props.children}
</ol>
);
const Link = props => {
const data = props.node.get('data');
const marks = data.get('marks');
const url = data.get('url');
const title = data.get('title');
const link = <a href={url} title={title} {...props.attributes}>{props.children}</a>;
const result = !marks ? link : marks.reduce((acc, mark) => {
return renderMark({ mark, children: acc });
}, link);
const link = (
<a href={url} title={title} {...props.attributes}>
{props.children}
</a>
);
const result = !marks
? link
: marks.reduce((acc, mark) => {
return renderMark({ mark, children: acc });
}, link);
return result;
};
const Image = props => {
@ -53,42 +69,67 @@ const Image = props => {
const url = data.get('url');
const title = data.get('title');
const alt = data.get('alt');
const image = <img src={url} title={title} alt={alt} {...props.attributes}/>;
const result = !marks ? image : marks.reduce((acc, mark) => {
return renderMark({ mark, children: acc });
}, image);
const image = <img src={url} title={title} alt={alt} {...props.attributes} />;
const result = !marks
? image
: marks.reduce((acc, mark) => {
return renderMark({ mark, children: acc });
}, image);
return result;
};
export const renderMark = props => {
switch (props.mark.type) {
case 'bold': return <Bold {...props}/>;
case 'italic': return <Italic {...props}/>;
case 'strikethrough': return <Strikethrough {...props}/>;
case 'code': return <Code {...props}/>;
case 'bold':
return <Bold {...props} />;
case 'italic':
return <Italic {...props} />;
case 'strikethrough':
return <Strikethrough {...props} />;
case 'code':
return <Code {...props} />;
}
};
export const renderNode = props => {
switch (props.node.type) {
case 'paragraph': return <Paragraph {...props}/>;
case 'list-item': return <ListItem {...props}/>;
case 'quote': return <Quote {...props}/>;
case 'code': return <CodeBlock {...props}/>;
case 'heading-one': return <HeadingOne {...props}/>;
case 'heading-two': return <HeadingTwo {...props}/>;
case 'heading-three': return <HeadingThree {...props}/>;
case 'heading-four': return <HeadingFour {...props}/>;
case 'heading-five': return <HeadingFive {...props}/>;
case 'heading-six': return <HeadingSix {...props}/>;
case 'table': return <Table {...props}/>;
case 'table-row': return <TableRow {...props}/>;
case 'table-cell': return <TableCell {...props}/>;
case 'thematic-break': return <ThematicBreak {...props}/>;
case 'bulleted-list': return <BulletedList {...props}/>;
case 'numbered-list': return <NumberedList {...props}/>;
case 'link': return <Link {...props}/>;
case 'image': return <Image {...props}/>;
case 'shortcode': return <Shortcode {...props}/>;
case 'paragraph':
return <Paragraph {...props} />;
case 'list-item':
return <ListItem {...props} />;
case 'quote':
return <Quote {...props} />;
case 'code':
return <CodeBlock {...props} />;
case 'heading-one':
return <HeadingOne {...props} />;
case 'heading-two':
return <HeadingTwo {...props} />;
case 'heading-three':
return <HeadingThree {...props} />;
case 'heading-four':
return <HeadingFour {...props} />;
case 'heading-five':
return <HeadingFive {...props} />;
case 'heading-six':
return <HeadingSix {...props} />;
case 'table':
return <Table {...props} />;
case 'table-row':
return <TableRow {...props} />;
case 'table-cell':
return <TableCell {...props} />;
case 'thematic-break':
return <ThematicBreak {...props} />;
case 'bulleted-list':
return <BulletedList {...props} />;
case 'numbered-list':
return <NumberedList {...props} />;
case 'link':
return <Link {...props} />;
case 'image':
return <Image {...props} />;
case 'shortcode':
return <Shortcode {...props} />;
}
};

View File

@ -66,24 +66,24 @@ export function validateNode(node) {
if (trailingShortcode) {
return change => {
const text = Text.create('');
const block = Block.create({ type: 'paragraph', nodes: [ text ] });
const block = Block.create({ type: 'paragraph', nodes: [text] });
return change.insertNodeByKey(doc.key, doc.get('nodes').size, block);
};
}
}
/**
* Ensure that code blocks contain no marks.
*/
if (node.type === 'code') {
const invalidChild = node.getTexts().find(text => !text.getMarks().isEmpty());
if (invalidChild) {
return change => (
invalidChild.getMarks().forEach(mark => (
change.removeMarkByKey(invalidChild.key, 0, invalidChild.get('characters').size, mark)
))
);
return change =>
invalidChild
.getMarks()
.forEach(mark =>
change.removeMarkByKey(invalidChild.key, 0, invalidChild.get('characters').size, mark),
);
}
}
}

View File

@ -39,12 +39,21 @@ export default css`
margin-top: 8px;
}
h1, h2, h3, h4, h5, h6 {
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 700;
line-height: 1;
}
p, pre, blockquote, ul, ol {
p,
pre,
blockquote,
ul,
ol {
margin-top: 16px;
margin-bottom: 16px;
}
@ -62,7 +71,8 @@ export default css`
margin: 0;
}
ul, ol {
ul,
ol {
padding-left: 30px;
}
@ -98,7 +108,8 @@ export default css`
border-collapse: collapse;
}
td, th {
td,
th {
border: 2px solid black;
padding: 8px;
text-align: left;

View File

@ -8,7 +8,7 @@ const MarkdownPreview = ({ value, getAsset }) => {
return null;
}
const html = markdownToHtml(value, getAsset);
return <WidgetPreviewContainer dangerouslySetInnerHTML={{__html: html}}/>
return <WidgetPreviewContainer dangerouslySetInnerHTML={{ __html: html }} />;
};
MarkdownPreview.propTypes = {

View File

@ -35,18 +35,18 @@ Text with **bold** & _em_ elements
###### H6
`;
expect(
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON()
).toMatchSnapshot()
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON(),
).toMatchSnapshot();
});
});
describe('Headings', () => {
for (const heading of [...Array(6).keys()]) {
it(`should render Heading ${ heading + 1 }`, () => {
it(`should render Heading ${heading + 1}`, () => {
const value = padStart(' Title', heading + 7, '#');
expect(
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON()
).toMatchSnapshot()
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON(),
).toMatchSnapshot();
});
}
});
@ -65,8 +65,8 @@ Text with **bold** & _em_ elements
1. ol item 3
`;
expect(
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON()
).toMatchSnapshot()
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON(),
).toMatchSnapshot();
});
});
@ -80,8 +80,8 @@ I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3]
[3]: http://search.msn.com/ "MSN Search"
`;
expect(
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON()
).toMatchSnapshot()
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON(),
).toMatchSnapshot();
});
});
@ -89,15 +89,15 @@ I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3]
it('should render code', () => {
const value = 'Use the `printf()` function.';
expect(
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON()
).toMatchSnapshot()
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON(),
).toMatchSnapshot();
});
it('should render code 2', () => {
const value = '``There is a literal backtick (`) here.``';
expect(
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON()
).toMatchSnapshot()
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON(),
).toMatchSnapshot();
});
});
@ -119,8 +119,8 @@ I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3]
<h1 style="display: block; border: 10px solid #f00; width: 100%">Test</h1>
`;
expect(
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON()
).toMatchSnapshot()
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON(),
).toMatchSnapshot();
});
});
});
@ -129,8 +129,8 @@ I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3]
it('should render HTML', () => {
const value = '<p>Paragraph with <em>inline</em> element</p>';
expect(
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON()
).toMatchSnapshot()
renderer.create(<MarkdownPreview value={markdownToHtml(value)} />).toJSON(),
).toMatchSnapshot();
});
});
});

View File

@ -1,2 +1,2 @@
export MarkdownControl from './MarkdownControl'
export MarkdownPreview from './MarkdownPreview'
export MarkdownControl from './MarkdownControl';
export MarkdownPreview from './MarkdownPreview';

View File

@ -8,7 +8,6 @@ export function joinPatternSegments(patterns) {
return patterns.map(p => p.source).join('');
}
/**
* Combines an array of regular expressions into a single expression, wrapping
* each in a non-capturing group and interposing alternation characters (|) so
@ -18,7 +17,6 @@ export function combinePatterns(patterns) {
return patterns.map(p => `(?:${p.source})`).join('|');
}
/**
* Modify substrings within a string if they match a (global) pattern. Can be
* inverted to only modify non-matches.
@ -63,34 +61,28 @@ export function replaceWhen(matchPattern, replaceFn, text, invertMatchPattern) {
*/
if (match.index === 0) {
addSubstring(acc, 0, match[0], true);
}
/**
* If there are no entries in the accumulator, convert the substring before
* the match to a data object (without the `match` flag set to true) and
* push to the accumulator, followed by a data object for the matching
* substring.
*/
else if (!lastEntry) {
} else if (!lastEntry) {
/**
* If there are no entries in the accumulator, convert the substring before
* the match to a data object (without the `match` flag set to true) and
* push to the accumulator, followed by a data object for the matching
* substring.
*/
addSubstring(acc, 0, match.input.slice(0, match.index));
addSubstring(acc, match.index, match[0], true);
}
/**
* If the last entry in the accumulator immediately preceded the current
* matched substring in the original string, just add the data object for
* the matching substring to the accumulator.
*/
else if (match.index === lastEntry.index + lastEntry.text.length) {
} else if (match.index === lastEntry.index + lastEntry.text.length) {
/**
* If the last entry in the accumulator immediately preceded the current
* matched substring in the original string, just add the data object for
* the matching substring to the accumulator.
*/
addSubstring(acc, match.index, match[0], true);
}
/**
* Convert the substring before the match to a data object (without the
* `match` flag set to true), followed by a data object for the matching
* substring.
*/
else {
} else {
/**
* Convert the substring before the match to a data object (without the
* `match` flag set to true), followed by a data object for the matching
* substring.
*/
const nextIndex = lastEntry.index + lastEntry.text.length;
const nextText = match.input.slice(nextIndex, match.index);
addSubstring(acc, nextIndex, nextText);

View File

@ -3,7 +3,10 @@ import markdownToRemark from 'remark-parse';
import remarkAllowHtmlEntities from '../remarkAllowHtmlEntities';
const process = markdown => {
const mdast = unified().use(markdownToRemark).use(remarkAllowHtmlEntities).parse(markdown);
const mdast = unified()
.use(markdownToRemark)
.use(remarkAllowHtmlEntities)
.parse(markdown);
/**
* The MDAST will look like:

View File

@ -7,23 +7,23 @@ describe('remarkAssertParents', () => {
it('should unnest invalidly nested blocks', () => {
const input = u('root', [
u('paragraph', [
u('paragraph', [ u('text', 'Paragraph text.') ]),
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
u('paragraph', [u('text', 'Paragraph text.')]),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('code', 'someCode()'),
u('blockquote', [ u('text', 'Quote text.') ]),
u('list', [ u('listItem', [ u('text', 'A list item.') ]) ]),
u('table', [ u('tableRow', [ u('tableCell', [ u('text', 'Text in a table cell.') ]) ]) ]),
u('blockquote', [u('text', 'Quote text.')]),
u('list', [u('listItem', [u('text', 'A list item.')])]),
u('table', [u('tableRow', [u('tableCell', [u('text', 'Text in a table cell.')])])]),
u('thematicBreak'),
]),
]);
const output = u('root', [
u('paragraph', [ u('text', 'Paragraph text.') ]),
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
u('paragraph', [u('text', 'Paragraph text.')]),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('code', 'someCode()'),
u('blockquote', [ u('text', 'Quote text.') ]),
u('list', [ u('listItem', [ u('text', 'A list item.') ]) ]),
u('table', [ u('tableRow', [ u('tableCell', [ u('text', 'Text in a table cell.') ]) ]) ]),
u('blockquote', [u('text', 'Quote text.')]),
u('list', [u('listItem', [u('text', 'A list item.')])]),
u('table', [u('tableRow', [u('tableCell', [u('text', 'Text in a table cell.')])])]),
u('thematicBreak'),
]);
@ -35,20 +35,14 @@ describe('remarkAssertParents', () => {
u('paragraph', [
u('paragraph', [
u('paragraph', [
u('paragraph', [ u('text', 'Paragraph text.') ]),
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
u('paragraph', [u('text', 'Paragraph text.')]),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('code', 'someCode()'),
u('blockquote', [
u('paragraph', [
u('strong', [
u('heading', [
u('text', 'Quote text.'),
]),
]),
]),
u('paragraph', [u('strong', [u('heading', [u('text', 'Quote text.')])])]),
]),
u('list', [ u('listItem', [ u('text', 'A list item.') ]) ]),
u('table', [ u('tableRow', [ u('tableCell', [ u('text', 'Text in a table cell.') ]) ]) ]),
u('list', [u('listItem', [u('text', 'A list item.')])]),
u('table', [u('tableRow', [u('tableCell', [u('text', 'Text in a table cell.')])])]),
u('thematicBreak'),
]),
]),
@ -56,16 +50,12 @@ describe('remarkAssertParents', () => {
]);
const output = u('root', [
u('paragraph', [ u('text', 'Paragraph text.') ]),
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
u('paragraph', [u('text', 'Paragraph text.')]),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('code', 'someCode()'),
u('blockquote', [
u('heading', [
u('text', 'Quote text.'),
]),
]),
u('list', [ u('listItem', [ u('text', 'A list item.') ]) ]),
u('table', [ u('tableRow', [ u('tableCell', [ u('text', 'Text in a table cell.') ]) ]) ]),
u('blockquote', [u('heading', [u('text', 'Quote text.')])]),
u('list', [u('listItem', [u('text', 'A list item.')])]),
u('table', [u('tableRow', [u('tableCell', [u('text', 'Text in a table cell.')])])]),
u('thematicBreak'),
]);
@ -74,42 +64,30 @@ describe('remarkAssertParents', () => {
it('should remove blocks that are emptied as a result of denesting', () => {
const input = u('root', [
u('paragraph', [
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
]),
u('paragraph', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]),
]);
const output = u('root', [
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
]);
const output = u('root', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]);
expect(transform(input)).toEqual(output);
});
it('should remove blocks that are emptied as a result of denesting', () => {
const input = u('root', [
u('paragraph', [
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
]),
u('paragraph', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]),
]);
const output = u('root', [
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
]);
const output = u('root', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]);
expect(transform(input)).toEqual(output);
});
it('should handle assymetrical splits', () => {
const input = u('root', [
u('paragraph', [
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
]),
u('paragraph', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]),
]);
const output = u('root', [
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
]);
const output = u('root', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]);
expect(transform(input)).toEqual(output);
});
@ -117,18 +95,12 @@ describe('remarkAssertParents', () => {
it('should nest invalidly nested blocks in the nearest valid ancestor', () => {
const input = u('root', [
u('paragraph', [
u('blockquote', [
u('strong', [
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
]),
]),
u('blockquote', [u('strong', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])])]),
]),
]);
const output = u('root', [
u('blockquote', [
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
]),
u('blockquote', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]),
]);
expect(transform(input)).toEqual(output);
@ -140,7 +112,7 @@ describe('remarkAssertParents', () => {
u('blockquote', [
u('strong', [
u('text', 'Deep validly nested text a.'),
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('text', 'Deep validly nested text b.'),
]),
]),
@ -150,17 +122,11 @@ describe('remarkAssertParents', () => {
const output = u('root', [
u('blockquote', [
u('strong', [
u('text', 'Deep validly nested text a.'),
]),
u('heading', { depth: 1 }, [ u('text', 'Heading text.') ]),
u('strong', [
u('text', 'Deep validly nested text b.'),
]),
]),
u('paragraph', [
u('text', 'Validly nested text.'),
u('strong', [u('text', 'Deep validly nested text a.')]),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('strong', [u('text', 'Deep validly nested text b.')]),
]),
u('paragraph', [u('text', 'Validly nested text.')]),
]);
expect(transform(input)).toEqual(output);
@ -174,7 +140,7 @@ describe('remarkAssertParents', () => {
u('table', [
u('tableRow', [
u('tableCell', [
u('heading', { depth: 1 }, [ u('text', 'Validly nested heading text.') ]),
u('heading', { depth: 1 }, [u('text', 'Validly nested heading text.')]),
]),
]),
]),
@ -190,7 +156,7 @@ describe('remarkAssertParents', () => {
u('table', [
u('tableRow', [
u('tableCell', [
u('heading', { depth: 1 }, [ u('text', 'Validly nested heading text.') ]),
u('heading', { depth: 1 }, [u('text', 'Validly nested heading text.')]),
]),
]),
]),

View File

@ -3,7 +3,7 @@ import u from 'unist-builder';
import remarkEscapeMarkdownEntities from '../remarkEscapeMarkdownEntities';
const process = text => {
const tree = u('root', [ u('text', text) ]);
const tree = u('root', [u('text', text)]);
const escapedMdast = unified()
.use(remarkEscapeMarkdownEntities)
.runSync(tree);
@ -22,8 +22,9 @@ describe('remarkEscapeMarkdownEntities', () => {
expect(process('[]')).toEqual('\\[]');
expect(process('[]()')).toEqual('\\[]()');
expect(process('[a](b)')).toEqual('\\[a](b)');
expect(process('[Test sentence.](https://www.example.com)'))
.toEqual('\\[Test sentence.](https://www.example.com)');
expect(process('[Test sentence.](https://www.example.com)')).toEqual(
'\\[Test sentence.](https://www.example.com)',
);
expect(process('![a](b)')).toEqual('!\\[a](b)');
});

View File

@ -8,15 +8,13 @@ const input = markdown =>
.use(markdownToRemark)
.use(remarkPaddedLinks)
.use(remarkToMarkdown)
.processSync(markdown)
.contents;
.processSync(markdown).contents;
const output = markdown =>
unified()
.use(markdownToRemark)
.use(remarkToMarkdown)
.processSync(markdown)
.contents;
.processSync(markdown).contents;
describe('remarkPaddedLinks', () => {
it('should move leading and trailing spaces outside of a link', () => {

View File

@ -56,7 +56,6 @@ import { getEditorComponents } from '../MarkdownControl';
* for serialization to/from Slate's Raw AST and MDAST.
*/
/**
* Deserialize a Markdown string to an MDAST.
*/
@ -82,17 +81,16 @@ export const markdownToRemark = markdown => {
return result;
};
/**
* Remove named tokenizers from the parser, effectively deactivating them.
*/
function markdownToRemarkRemoveTokenizers({ inlineTokenizers }) {
inlineTokenizers && inlineTokenizers.forEach(tokenizer => {
delete this.Parser.prototype.inlineTokenizers[tokenizer];
});
inlineTokenizers &&
inlineTokenizers.forEach(tokenizer => {
delete this.Parser.prototype.inlineTokenizers[tokenizer];
});
}
/**
* Serialize an MDAST to a Markdown string.
*/
@ -146,7 +144,6 @@ export const remarkToMarkdown = obj => {
return trimEnd(markdown);
};
/**
* Convert Markdown to HTML.
*/
@ -163,8 +160,7 @@ export const markdownToHtml = (markdown, getAsset) => {
.stringify(hast);
return html;
}
};
/**
* Deserialize an HTML string to Slate's Raw AST. Currently used for HTML
@ -192,7 +188,6 @@ export const htmlToSlate = html => {
return slateRaw;
};
/**
* Convert Markdown to Slate's Raw AST.
*/
@ -207,7 +202,6 @@ export const markdownToSlate = markdown => {
return slateRaw;
};
/**
* Convert a Slate Raw AST to Markdown.
*

View File

@ -13,7 +13,6 @@ const patternSegments = {
htmlOpeningTagEnd: /(?: *\w+=(?:(?:"[^"]*")|(?:'[^']*')))* *>/,
};
/**
* Patterns matching substrings that should not be escaped. Array values must be
* joined before use.
@ -37,7 +36,6 @@ const nonEscapePatterns = {
patternSegments.htmlOpeningTagEnd,
],
/**
* Preformatted HTML Blocks
*
@ -72,7 +70,6 @@ const nonEscapePatterns = {
],
};
/**
* Escape patterns
*
@ -137,7 +134,6 @@ const escapePatterns = [
/(\[)[^\]]*]/g,
];
/**
* Generate new non-escape expression. The non-escape expression matches
* substrings whose contents should not be processed for escaping.
@ -147,14 +143,12 @@ const joinedNonEscapePatterns = map(nonEscapePatterns, pattern => {
});
const nonEscapePattern = combinePatterns(joinedNonEscapePatterns);
/**
* Create chain of successive escape functions for various markdown entities.
*/
const escapeFunctions = escapePatterns.map(pattern => partial(escapeDelimiters, pattern));
const escapeAll = flow(escapeFunctions);
/**
* Executes both the `escapeCommonChars` and `escapeLeadingChars` functions.
*/
@ -163,7 +157,6 @@ function escapeAllChars(text) {
return escapeLeadingChars(partiallyEscapedMarkdown);
}
/**
* escapeLeadingChars
*
@ -178,7 +171,6 @@ function escapeLeadingChars(text) {
return text.replace(/^\s*([-#*>=|]| {4,}|`{3,})/, '$`\\$1');
}
/**
* escapeCommonChars
*
@ -199,7 +191,6 @@ function escapeCommonChars(text) {
return replaceWhen(nonEscapeExpression, escapeAll, text, true);
}
/**
* escapeDelimiters
*
@ -216,7 +207,6 @@ function escapeDelimiters(pattern, text) {
});
}
/**
* escape
*
@ -231,7 +221,6 @@ function escape(delim) {
return result;
}
/**
* A Remark plugin for escaping markdown entities.
*
@ -261,7 +250,6 @@ export default function remarkEscapeMarkdownEntities() {
* text in html nodes to keep Remark from escaping html entities.
*/
if (['text', 'html'].includes(node.type)) {
/**
* Escape all characters if this is the first child node, otherwise only
* common characters.
@ -273,7 +261,7 @@ export default function remarkEscapeMarkdownEntities() {
/**
* Always return nodes with recursively mapped children.
*/
return {...node, children };
return { ...node, children };
};
return transform;

View File

@ -11,9 +11,9 @@ export default function remarkImagesToText() {
function transform(node) {
const children = node.children.map(child => {
if (
child.type === 'paragraph'
&& child.children.length === 1
&& child.children[0].type === 'image'
child.type === 'paragraph' &&
child.children.length === 1 &&
child.children[0].type === 'image'
) {
const { alt = '', url = '', title = '' } = child.children[0];
const value = `![${alt}](${url}${title ? ' title' : ''})`;

View File

@ -1,12 +1,4 @@
import {
find,
findLast,
startsWith,
endsWith,
trimStart,
trimEnd,
flatMap
} from 'lodash';
import { find, findLast, startsWith, endsWith, trimStart, trimEnd, flatMap } from 'lodash';
import u from 'unist-builder';
import toString from 'mdast-util-to-string';
@ -20,9 +12,7 @@ import toString from 'mdast-util-to-string';
* children one at a time.
*/
export default function remarkPaddedLinks() {
function transform(node) {
/**
* Because we're operating on link nodes and their children at once, we can
* exit if the current node has no children.
@ -40,7 +30,9 @@ export default function remarkPaddedLinks() {
* this seems unlikely to produce a noticeable perf gain.
*/
const hasLinkChild = node.children.some(child => child.type === 'link');
const processedChildren = hasLinkChild ? flatMap(node.children, transformChildren) : node.children;
const processedChildren = hasLinkChild
? flatMap(node.children, transformChildren)
: node.children;
/**
* Run all children through the transform recursively.
@ -83,7 +75,7 @@ export default function remarkPaddedLinks() {
const nodes = [
leadingWhitespaceNode && u('text', ' '),
node,
trailingWhitespaceNode && u('text', ' ')
trailingWhitespaceNode && u('text', ' '),
];
return nodes.filter(val => val);
@ -95,14 +87,17 @@ export default function remarkPaddedLinks() {
*/
function getEdgeTextChild(node, end) {
/**
* This was changed from a ternary to a long form if due to issues with istanbul's instrumentation and babel's code
* generation.
* This was changed from a ternary to a long form if due to issues with istanbul's instrumentation and babel's code
* generation.
* TODO: watch https://github.com/istanbuljs/babel-plugin-istanbul/issues/95
* when it is resolved then revert to ```const findFn = end ? findLast : find;```
*/
let findFn;
if (end) { findFn = findLast }
else { findFn = find }
if (end) {
findFn = findLast;
} else {
findFn = find;
}
let edgeChildWithValue;
setEdgeChildWithValue(node);

View File

@ -44,7 +44,7 @@ export default function remarkToRehypeShortcodes({ plugins, getAsset }) {
* Return a new 'html' type node containing the shortcode preview markup.
*/
const textNode = u('html', valueHtml);
const children = [ textNode ];
const children = [textNode];
return { ...node, children };
}
}

View File

@ -9,7 +9,6 @@ export default function remarkToSlate() {
}
function transform(node) {
/**
* Call `transform` recursively on child nodes.
*
@ -17,9 +16,10 @@ function transform(node) {
* translate from MDAST to Slate, such as definitions for link/image
* references or footnotes.
*/
const children = !['strong', 'emphasis', 'delete'].includes(node.type)
&& !isEmpty(node.children)
&& flatMap(node.children, transform).filter(val => val);
const children =
!['strong', 'emphasis', 'delete'].includes(node.type) &&
!isEmpty(node.children) &&
flatMap(node.children, transform).filter(val => val);
/**
* Run individual nodes through the conversion factory.
@ -45,7 +45,6 @@ const typeMap = {
shortcode: 'shortcode',
};
/**
* Map of MDAST node types to Slate mark types.
*/
@ -56,7 +55,6 @@ const markMap = {
inlineCode: 'code',
};
/**
* Add nodes to a parent node only if `nodes` is truthy.
*/
@ -64,7 +62,6 @@ function addNodes(parent, nodes) {
return nodes ? { ...parent, nodes } : parent;
}
/**
* Create a Slate Inline node.
*/
@ -78,7 +75,6 @@ function createBlock(type, nodes, props = {}) {
return addNodes(node, nodes);
}
/**
* Create a Slate Block node.
*/
@ -87,7 +83,6 @@ function createInline(type, props = {}, nodes) {
return addNodes(node, nodes);
}
/**
* Create a Slate Raw text node.
*/
@ -122,7 +117,7 @@ function processMarkNode(node, parentMarks = []) {
* first add the inline code mark to the marks array.
*/
case 'inlineCode': {
const childMarks = [ ...marks, { type: markMap['inlineCode'] } ];
const childMarks = [...marks, { type: markMap['inlineCode'] }];
return { text: childNode.value, marks: childMarks };
}
@ -156,11 +151,9 @@ function convertMarkNode(node) {
const lastConvertedNode = last(acc);
if (node.text && lastConvertedNode && lastConvertedNode.leaves) {
lastConvertedNode.leaves.push(node);
}
else if (node.text) {
} else if (node.text) {
acc.push(createText([node]));
}
else {
} else {
acc.push(transform(node));
}
@ -176,7 +169,6 @@ function convertMarkNode(node) {
* transformer.
*/
function convertNode(node, nodes) {
/**
* Unified/Remark processors use mutable operations, so we don't want to
* change a node's type directly for conversion purposes, as that tends to
@ -185,7 +177,6 @@ function convertNode(node, nodes) {
const type = get(node, ['data', 'shortcode']) ? 'shortcode' : node.type;
switch (type) {
/**
* General
*
@ -201,7 +192,6 @@ function convertNode(node, nodes) {
return createBlock(typeMap[type], nodes);
}
/**
* Shortcodes
*
@ -211,7 +201,7 @@ function convertNode(node, nodes) {
*/
case 'shortcode': {
const { data } = node;
const nodes = [ createText('') ];
const nodes = [createText('')];
return createBlock(typeMap[type], nodes, { data, isVoid: true });
}
@ -240,7 +230,7 @@ function convertNode(node, nodes) {
text: node.value,
marks: [{ type: 'code' }],
};
return createText([ leaf ]);
return createText([leaf]);
}
/**
@ -308,7 +298,7 @@ function convertNode(node, nodes) {
*/
case 'break': {
const textNode = createText('\n');
return createInline('break', {}, [ textNode ]);
return createInline('break', {}, [textNode]);
}
/**
@ -345,7 +335,6 @@ function convertNode(node, nodes) {
return createInline(typeMap[type], { isVoid: true, data: newData });
}
/**
* Tables
*

View File

@ -32,7 +32,6 @@ export default function remarkSquashReferences() {
}
function transform(getDefinition, node) {
/**
* Bind the `getDefinition` function to `transform` and recursively map all
* nodes.
@ -55,15 +54,15 @@ export default function remarkSquashReferences() {
const pre = u('text', node.type === 'imageReference' ? '![' : '[');
const post = u('text', ']');
const nodes = children || [ u('text', node.alt) ];
return [ pre, ...nodes, post];
const nodes = children || [u('text', node.alt)];
return [pre, ...nodes, post];
}
/**
* Remove definition nodes and filter the resulting null values from the
* filtered children array.
*/
if(node.type === 'definition') {
if (node.type === 'definition') {
return null;
}

View File

@ -14,7 +14,6 @@ export default function remarkStripTrailingBreaks() {
if (node.children) {
node.children = node.children
.map((child, idx, children) => {
/**
* Only touch break nodes. Convert all subsequent nodes to their text
* value and exclude the break node if no non-whitespace characters

View File

@ -5,7 +5,6 @@ import u from 'unist-builder';
* are used for text nodes that we don't want Remark or Rehype to parse.
*/
export default function remarkWrapHtml() {
function transform(tree) {
tree.children = tree.children.map(node => {
if (node.type === 'html') {

View File

@ -5,29 +5,28 @@ import u from 'unist-builder';
* Map of Slate node types to MDAST/Remark node types.
*/
const typeMap = {
'root': 'root',
'paragraph': 'paragraph',
root: 'root',
paragraph: 'paragraph',
'heading-one': 'heading',
'heading-two': 'heading',
'heading-three': 'heading',
'heading-four': 'heading',
'heading-five': 'heading',
'heading-six': 'heading',
'quote': 'blockquote',
'code': 'code',
quote: 'blockquote',
code: 'code',
'numbered-list': 'list',
'bulleted-list': 'list',
'list-item': 'listItem',
'table': 'table',
table: 'table',
'table-row': 'tableRow',
'table-cell': 'tableCell',
'break': 'break',
break: 'break',
'thematic-break': 'thematicBreak',
'link': 'link',
'image': 'image',
link: 'link',
image: 'image',
};
/**
* Map of Slate mark types to MDAST/Remark node types.
*/
@ -55,7 +54,6 @@ export default function slateToRemark(raw, opts) {
return transform(raw);
}
/**
* The transform function mimics the approach of a Remark plugin for
* conformity with the other serialization functions. This function converts
@ -83,7 +81,6 @@ function transform(node) {
: convertNode(node, children, shortcodePlugins);
}
/**
* Includes inline nodes as leaves in adjacent text nodes where appropriate, so
* that mark node combining logic can apply to both text and inline nodes. This
@ -140,7 +137,6 @@ function combineTextAndInline(nodes) {
}, []);
}
/**
* Slate treats inline code decoration as a standard mark, but MDAST does
* not allow inline code nodes to contain children, only a single text
@ -232,7 +228,6 @@ function convertTextNode(node) {
return u('html', node.text);
}
/**
* Process Slate node leaves in preparation for MDAST transformation.
*/
@ -256,7 +251,6 @@ function processLeaves(leaf) {
return { node: leaf.node, marks: markTypes };
}
/**
* Slate's AST doesn't group adjacent text nodes with the same marks - a
* change in marks from letter to letter, even if some are in common, results
@ -311,47 +305,51 @@ function condenseNodesReducer(acc, node, idx, nodes) {
* children.
*/
const children = nodes.slice(idx, newNextIndex);
const denestedChildren = children.map(child => ({ ...child, marks: without(child.marks, parentType) }));
const mdastChildren = denestedChildren.reduce(condenseNodesReducer, { nodes: [], parentType }).nodes;
const denestedChildren = children.map(child => ({
...child,
marks: without(child.marks, parentType),
}));
const mdastChildren = denestedChildren.reduce(condenseNodesReducer, { nodes: [], parentType })
.nodes;
const mdastNode = u(parentType, mdastChildren);
return { ...acc, nodes: [ ...acc.nodes, mdastNode ], nextIndex: newNextIndex };
return { ...acc, nodes: [...acc.nodes, mdastNode], nextIndex: newNextIndex };
}
/**
* Create the base text node, and pass in the array of mark types as data
* (helpful when optimizing/condensing the final structure).
*/
const baseNode = typeof node.text === 'string'
? u(node.textNodeType, { marks: node.marks }, node.text)
: transform(node.node);
const baseNode =
typeof node.text === 'string'
? u(node.textNodeType, { marks: node.marks }, node.text)
: transform(node.node);
/**
* Recursively wrap the base text node in the individual mark nodes, if
* any exist.
*/
return { ...acc, nodes: [ ...acc.nodes, baseNode ] };
return { ...acc, nodes: [...acc.nodes, baseNode] };
}
/**
* Get the number of consecutive Slate nodes containing a given mark beginning
* from the first received node.
*/
function getMarkLength(markType, nodes) {
let length = 0;
while(nodes[length] && nodes[length].marks.includes(markType)) { ++length; }
while (nodes[length] && nodes[length].marks.includes(markType)) {
++length;
}
return { markType, length };
}
/**
* Convert a single Slate Raw node to an MDAST node. Uses the unist-builder `u`
* function to create MDAST nodes and parses shortcodes.
*/
function convertNode(node, children, shortcodePlugins) {
switch (node.type) {
/**
* General
*
@ -390,7 +388,7 @@ function convertNode(node, children, shortcodePlugins) {
const plugin = shortcodePlugins.get(data.shortcode);
const text = plugin.toBlock(data.shortcodeData);
const textNode = u('html', text);
return u('paragraph', { data }, [ textNode ]);
return u('paragraph', { data }, [textNode]);
}
/**
@ -480,7 +478,6 @@ function convertNode(node, children, shortcodePlugins) {
return u(typeMap[node.type], { url, title, alt, data });
}
/**
* No default case is supplied because an unhandled case should never
* occur. In the event that it does, let the error throw (for now).

View File

@ -9,4 +9,4 @@ export const EditorControlBar = styled.div`
position: sticky;
top: 0;
margin-bottom: ${editorStyleVars.stickyDistanceBottom};
`
`;