Skip to content

Commit

Permalink
Light refactor to pull some functions out of the main closure
Browse files Browse the repository at this point in the history
  • Loading branch information
Evan Jacobs committed Sep 16, 2016
1 parent a78c382 commit c381ddd
Showing 1 changed file with 144 additions and 147 deletions.
291 changes: 144 additions & 147 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,150 +6,181 @@ import get from 'lodash.get';
const getType = Object.prototype.toString;
const textTypes = ['text', 'textNode'];

export default function markdownToJSX(markdown, options = {}, overrides = {}) {
let definitions;
let footnotes;
function extractDefinitionsFromASTTree(ast, parser) {
function reducer(aggregator, node) {
if (node.type === 'definition' || node.type === 'footnoteDefinition') {
aggregator.definitions[node.identifier] = node;

if (node.type === 'footnoteDefinition') {
if ( node.children
&& node.children.length === 1
&& node.children[0].type === 'paragraph') {
node.children[0].children.unshift({
type: 'textNode',
value: `[${node.identifier}]: `,
});
} /* package the prefix inside the first child */

aggregator.footnotes.push(
<div key={node.identifier} id={node.identifier}>
{node.value || node.children.map(parser)}
</div>
);
}
}

function getHTMLNodeTypeFromASTNodeType(node) {
switch (node.type) {
case 'break':
return 'br';
return Array.isArray(node.children)
? node.children.reduce(reducer, aggregator)
: aggregator;
};

case 'delete':
return 'del';
return [ast].reduce(reducer, {
definitions: {},
footnotes: []
});
}

case 'emphasis':
return 'em';
function formExtraPropsForHTMLNodeType(props = {}, ast, definitions) {
switch (ast.type) {
case 'footnoteReference':
return {
...props,
href: `#${ast.identifier}`,
};

case 'footnoteReference':
return 'a';
case 'image':
return {
...props,
title: ast.title,
alt: ast.alt,
src: ast.url,
};

case 'heading':
return `h${node.depth}`;
case 'imageReference':
return {
...props,
title: get(definitions, `['${ast.identifier}'].title`),
alt: ast.alt,
src: get(definitions, `['${ast.identifier}'].url`),
};

case 'html':
return 'div';
case 'link':
return {
...props,
title: ast.title,
href: ast.url,
};

case 'image':
case 'imageReference':
return 'img';
case 'linkReference':
return {
...props,
title: get(definitions, `['${ast.identifier}'].title`),
href: get(definitions, `['${ast.identifier}'].url`),
};

case 'inlineCode':
return 'code';
case 'list':
return {
...props,
start: ast.start,
};

case 'link':
case 'linkReference':
return 'a';
case 'tableCell':
case 'th':
return {
...props,
style: {textAlign: ast.align},
};
}

case 'list':
return node.ordered ? 'ol' : 'ul';
return props;
}

case 'listItem':
return 'li';
function getHTMLNodeTypeFromASTNodeType(node) {
switch (node.type) {
case 'break':
return 'br';

case 'paragraph':
return 'p';
case 'delete':
return 'del';

case 'root':
return 'div';
case 'emphasis':
return 'em';

case 'tableHeader':
return 'thead';
case 'footnoteReference':
return 'a';

case 'tableRow':
return 'tr';
case 'heading':
return `h${node.depth}`;

case 'tableCell':
return 'td';
case 'image':
case 'imageReference':
return 'img';

case 'thematicBreak':
return 'hr';
case 'inlineCode':
return 'code';

case 'definition':
case 'footnoteDefinition':
case 'yaml':
return null;
case 'link':
case 'linkReference':
return 'a';

default:
return node.type;
}
}
case 'list':
return node.ordered ? 'ol' : 'ul';

function formExtraPropsForHTMLNodeType(props = {}, ast) {
switch (ast.type) {
case 'footnoteReference':
return {
...props,
href: `#${ast.identifier}`,
};
case 'listItem':
return 'li';

case 'image':
return {
...props,
title: ast.title,
alt: ast.alt,
src: ast.url,
};
case 'paragraph':
return 'p';

case 'imageReference':
return {
...props,
title: get(definitions, `['${ast.identifier}'].title`),
alt: ast.alt,
src: get(definitions, `['${ast.identifier}'].url`),
};
case 'root':
return 'div';

case 'link':
return {
...props,
title: ast.title,
href: ast.url,
};
case 'tableHeader':
return 'thead';

case 'linkReference':
return {
...props,
title: get(definitions, `['${ast.identifier}'].title`),
href: get(definitions, `['${ast.identifier}'].url`),
};
case 'tableRow':
return 'tr';

case 'list':
return {
...props,
start: ast.start,
};
case 'tableCell':
return 'td';

case 'thematicBreak':
return 'hr';

case 'definition':
case 'footnoteDefinition':
case 'yaml':
return null;

default:
return node.type;
}
}

case 'tableCell':
case 'th':
function seekCellsAndAlignThemIfNecessary(root, alignmentValues) {
const mapper = (child, index) => {
if (child.type === 'tableCell') {
return {
...props,
style: {textAlign: ast.align},
...child,
align: alignmentValues[index],
};
} else if (Array.isArray(child.children) && child.children.length) {
return child.children.map(mapper);
}

return props;
}

function seekCellsAndAlignThemIfNecessary(root, alignmentValues) {
const mapper = (child, index) => {
if (child.type === 'tableCell') {
return {
...child,
align: alignmentValues[index],
};
} else if (Array.isArray(child.children) && child.children.length) {
return child.children.map(mapper);
}
return child;
};

return child;
};
if (Array.isArray(root.children) && root.children.length) {
root.children = root.children.map(mapper);
}

if (Array.isArray(root.children) && root.children.length) {
root.children = root.children.map(mapper);
}
return root;
}

return root;
}
export default function markdownToJSX(markdown, options = {}, overrides = {}) {
let definitions;
let footnotes;

function astToJSX(ast, index) { /* `this` is the dictionary of definitions */
if (textTypes.indexOf(ast.type) !== -1) {
Expand Down Expand Up @@ -278,7 +309,7 @@ export default function markdownToJSX(markdown, options = {}, overrides = {}) {
(necessary evil, file an issue if something comes up that needs
extra attention, only props specified in `formExtraPropsForHTMLNodeType`
will be overwritten on a key collision) */
const finalProps = formExtraPropsForHTMLNodeType(props, ast);
const finalProps = formExtraPropsForHTMLNodeType(props, ast, definitions);

if (ast.children && ast.children.length === 1) {
if (textTypes.indexOf(ast.children[0].type) !== -1) {
Expand All @@ -293,40 +324,6 @@ export default function markdownToJSX(markdown, options = {}, overrides = {}) {
return React.createElement(htmlNodeType, finalProps, ast.value || children);
}

function extractDefinitionsFromASTTree(ast) {
const reducer = (aggregator, node) => {
if (node.type === 'definition' || node.type === 'footnoteDefinition') {
aggregator.definitions[node.identifier] = node;

if (node.type === 'footnoteDefinition') {
if ( node.children
&& node.children.length === 1
&& node.children[0].type === 'paragraph') {
node.children[0].children.unshift({
type: 'textNode',
value: `[${node.identifier}]: `,
});
} /* package the prefix inside the first child */

aggregator.footnotes.push(
<div key={node.identifier} id={node.identifier}>
{node.value || node.children.map(astToJSX)}
</div>
);
}
}

return Array.isArray(node.children)
? node.children.reduce(reducer, aggregator)
: aggregator;
};

return [ast].reduce(reducer, {
definitions: {},
footnotes: []
});
}

if (typeof markdown !== 'string') {
throw new Error(`markdown-to-jsx: the first argument must be
a string`);
Expand All @@ -353,7 +350,7 @@ export default function markdownToJSX(markdown, options = {}, overrides = {}) {
options.footnotes = options.footnotes || true;

const remarkAST = unified().use(parser).parse(markdown, options);
const extracted = extractDefinitionsFromASTTree(remarkAST);
const extracted = extractDefinitionsFromASTTree(remarkAST, astToJSX);

definitions = extracted.definitions;
footnotes = extracted.footnotes;
Expand Down

0 comments on commit c381ddd

Please sign in to comment.