-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite
method-doc
to generate HTML directly
- Loading branch information
Showing
7 changed files
with
133 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@codewars/marked-extensions': minor | ||
--- | ||
|
||
Rewrite `method-doc` to generate HTML directly |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,151 +1,145 @@ | ||
import { escapeHtml } from './strings'; | ||
import { docGlobal } from './doc-tokens/doc-globals'; | ||
import { docName, docClass, docMethod } from './doc-tokens/doc-names'; | ||
import { docType } from './doc-tokens/doc-types'; | ||
|
||
export function methodDoc(code, language) { | ||
export function methodDoc(code, language, render) { | ||
try { | ||
let json = JSON.parse(code); | ||
const json = JSON.parse(code); | ||
|
||
// support language specific overrides | ||
if (json.languages && json.languages[language]) { | ||
Object.assign(json, json.languages[language]); | ||
} | ||
|
||
const md = []; | ||
const html = []; | ||
|
||
if (!json.examplesOnly) { | ||
if (json.method) { | ||
md.push(methodHeader(json)); | ||
html.push(methodHeader(json, language)); | ||
} | ||
if (json.desc) { | ||
md.push(json.desc); | ||
html.push(render(json.desc)); | ||
} | ||
|
||
md.push('```%doc'); | ||
|
||
html.push(`<div class="block block--doc">`); | ||
html.push(`<dl>`); | ||
if (json.args) { | ||
md.push('Parameters:'); | ||
md.push(parameters(json)); | ||
html.push(`<dt>Parameters</dt>`); | ||
html.push(parameters(json, language).map(markdownDefD(render)).join('\n')); | ||
} | ||
md.push('Return Value:'); | ||
md.push(returnType(json)); | ||
|
||
html.push(`<dt>Return Value</dt>`); | ||
html.push(`<dd>`); | ||
html.push(render(returnType(json, language))); | ||
html.push(`</dd>`); | ||
|
||
if (json.constraints && json.constraints.length) { | ||
md.push('Constraints:'); | ||
md.push(json.constraints.join('\n')); | ||
html.push(`<dt>Constraints</dt>`); | ||
html.push(json.constraints.map(markdownDefD(render)).join('\n')); | ||
} | ||
if (json.errors && json.errors.length) { | ||
md.push('Errors:'); | ||
md.push(json.errors.join('\n')); | ||
html.push(`<dt>Errors</dt>`); | ||
html.push(json.errors.map(markdownDefD(render)).join('\n')); | ||
} | ||
md.push('```'); | ||
|
||
html.push(`</dl>`); | ||
html.push(`</div>`); | ||
} | ||
|
||
if (json.examples && json.examples.length) { | ||
md.push('```%doc-block'); | ||
md.push('#### Examples'); | ||
md.push(exampleHeader(json)); | ||
md.push(exampleRows(json)); | ||
md.push('```'); | ||
html.push(`<div class="block block--doc-block">`); | ||
html.push(`<h4>Examples</h4>`); | ||
html.push(`<table>`); | ||
html.push(`<thead>`); | ||
html.push(exampleHeader(json)); | ||
html.push(`</thead>`); | ||
html.push(`<tbody>`); | ||
html.push(exampleRows(json)); | ||
html.push(`</tbody>`); | ||
html.push(`</table>`); | ||
html.push(`</div>`); | ||
} | ||
|
||
return md.join('\n'); | ||
return html.join('\n'); | ||
} catch (ex) { | ||
return '`Failed to render %jsonblock: ' + ex.message + '`'; | ||
return `<code>Failed to render %method-doc: ${escapeHtml(ex.message)}</code>`; | ||
} | ||
} | ||
|
||
const markdownDefD = (render) => (dd) => `<dd>${render(dd)}</dd>`; | ||
|
||
function hasExampleNames(json) { | ||
return json.examples && json.examples.filter((e) => !!e.name).length > 0; | ||
} | ||
|
||
function exampleRows(json) { | ||
const hasExamples = hasExampleNames(json); | ||
return json.examples.map((v) => exampleRow(json, v, hasExamples)).join('\n'); | ||
return json.examples.map((v) => `<tr>${exampleRow(v, hasExamples)}</tr>`).join('\n'); | ||
} | ||
|
||
function exampleRow(json, example, hasExamples) { | ||
let md = ''; | ||
function exampleRow(example, hasExamples) { | ||
const tds = []; | ||
if (hasExamples) { | ||
const name = example.name; | ||
md = `*${name || 'Example'}*|`; | ||
} | ||
|
||
if (example.args) { | ||
md += example.args.map((arg) => formatExampleValue(arg)).join('|'); | ||
tds.push(`<em>${example.name || 'Example'}</em>`); | ||
} | ||
md += `|${formatExampleValue(example.returns) || ''}`; | ||
return md; | ||
if (example.args) tds.push(...example.args.map(formatExampleValue)); | ||
tds.push(formatExampleValue(example.returns) || ''); | ||
return tds.map((t) => `<td>${t}</td>`).join(''); | ||
} | ||
|
||
function formatExampleValue(value) { | ||
return `<code>${JSON.stringify(value)}</code>`; | ||
} | ||
|
||
function exampleHeader(json) { | ||
const line1 = []; | ||
const line2 = []; | ||
if (hasExampleNames(json)) { | ||
line1.push('|'); | ||
line2.push(''); | ||
} | ||
|
||
Object.keys(getArgs(json)).forEach((key) => { | ||
line1.push(key); | ||
line2.push(''); | ||
}); | ||
line1.push('Return Value'); | ||
return `${line1.join('|')}\n-${line2.join('|-')}|-`; | ||
const keys = hasExampleNames(json) ? [''] : []; | ||
keys.push(...Object.keys(getArgs(json))); | ||
keys.push('Return Value'); | ||
return `<tr>${keys.map((k) => `<th>${k}</th>`).join('')}</tr>`; | ||
} | ||
|
||
function getArgs(json) { | ||
return json.args || json.params || json.parameters || {}; | ||
} | ||
|
||
function methodName(json) { | ||
let globalName = json.global !== false ? `@@docGlobal:${json.global || 'Challenge'}.` : ''; | ||
function methodName(json, language) { | ||
// if a class is provided, it will always be shown and overrides global | ||
if (json.class) { | ||
globalName = `@@docClass:${json.class}.`; | ||
} | ||
|
||
return `${globalName}@@docMethod:${json.method}`; | ||
const prefix = json.class | ||
? docClass(json.class, language) | ||
: json.global !== false | ||
? docGlobal(json.global || 'Challenge', language) | ||
: ''; | ||
return `${prefix}${prefix ? '.' : ''}${docMethod(json.method, language)}`; | ||
} | ||
|
||
function methodHeader(json) { | ||
const args = Object.keys(getArgs(json)).map((key) => `\`@@docName:${key}\``); | ||
return `### \`${methodName(json)}\`(${args.join(', ')})`; | ||
function methodHeader(json, language) { | ||
const args = Object.keys(getArgs(json)).map((key) => `<code>${docName(key, language)}</code>`); | ||
return `<h3><code>${methodName(json, language)}</code>(${args.join(', ')})</h3>`; | ||
} | ||
|
||
function parameters(json) { | ||
function parameters(json, language) { | ||
const args = getArgs(json); | ||
const params = Object.keys(args).map((key) => { | ||
return Object.keys(args).map((key) => { | ||
const arg = args[key]; | ||
const type = typeof arg === 'string' ? arg : arg.type; | ||
let md = `@@docName:${key}: ${formatDocType(json, type, 'String')}`; | ||
if (arg.desc) { | ||
md += ` - ${arg.desc}`; | ||
} | ||
|
||
return md; | ||
const md = `${docName(key, language)}: ${formatDocType(json, type, 'String', language)}`; | ||
return md + (arg.desc ? ` - ${arg.desc}` : ''); | ||
}); | ||
|
||
return params.join('\n'); | ||
} | ||
|
||
function returnType(json) { | ||
function returnType(json, language) { | ||
if (json.returns) { | ||
const type = typeof json.returns === 'string' ? json.returns : json.returns.type; | ||
let md = formatDocType(json, type, 'void'); | ||
if (json.returns.desc) { | ||
md += ` - ${json.returns.desc}`; | ||
} | ||
|
||
return md; | ||
const md = formatDocType(json, type, 'void', language); | ||
return md + (json.returns.desc ? ` - ${json.returns.desc}` : ''); | ||
} | ||
return '@@docType:void'; | ||
return docType('void', language); | ||
} | ||
|
||
function formatDocType(json, type, defaultValue) { | ||
function formatDocType(json, type, defaultValue, language) { | ||
if (json.formatTypes === false) { | ||
return `<dfn class="doc-type">${escapeHtml(type)}</dfn>`; | ||
} | ||
|
||
return `@@docType:${type || defaultValue || 'null'}`; | ||
return docType(type || defaultValue || 'null', language); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters