1
0
Fork 0

Merge pull request #1072 from actions/robherley/not-markdown-summaries

Rename core's `markdownSummary` extension to `summary`
pull/1073/head
Rob Herley 2022-05-05 14:17:33 -04:00 committed by GitHub
commit 01aceeaad6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 83 deletions

View File

@ -1,9 +1,10 @@
import * as fs from 'fs' import * as fs from 'fs'
import * as os from 'os' import * as os from 'os'
import path from 'path' import path from 'path'
import {markdownSummary, SUMMARY_ENV_VAR} from '../src/markdown-summary' import {summary, SUMMARY_ENV_VAR} from '../src/summary'
const testFilePath = path.join(__dirname, 'test', 'test-summary.md') const testDirectoryPath = path.join(__dirname, 'test')
const testFilePath = path.join(testDirectoryPath, 'test-summary.md')
async function assertSummary(expected: string): Promise<void> { async function assertSummary(expected: string): Promise<void> {
const file = await fs.promises.readFile(testFilePath, {encoding: 'utf8'}) const file = await fs.promises.readFile(testFilePath, {encoding: 'utf8'})
@ -67,11 +68,12 @@ const fixtures = {
} }
} }
describe('@actions/core/src/markdown-summary', () => { describe('@actions/core/src/summary', () => {
beforeEach(async () => { beforeEach(async () => {
process.env[SUMMARY_ENV_VAR] = testFilePath process.env[SUMMARY_ENV_VAR] = testFilePath
await fs.promises.mkdir(testDirectoryPath, {recursive: true})
await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'}) await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'})
markdownSummary.emptyBuffer() summary.emptyBuffer()
}) })
afterAll(async () => { afterAll(async () => {
@ -80,39 +82,39 @@ describe('@actions/core/src/markdown-summary', () => {
it('throws if summary env var is undefined', async () => { it('throws if summary env var is undefined', async () => {
process.env[SUMMARY_ENV_VAR] = undefined process.env[SUMMARY_ENV_VAR] = undefined
const write = markdownSummary.addRaw(fixtures.text).write() const write = summary.addRaw(fixtures.text).write()
await expect(write).rejects.toThrow() await expect(write).rejects.toThrow()
}) })
it('throws if summary file does not exist', async () => { it('throws if summary file does not exist', async () => {
await fs.promises.unlink(testFilePath) await fs.promises.unlink(testFilePath)
const write = markdownSummary.addRaw(fixtures.text).write() const write = summary.addRaw(fixtures.text).write()
await expect(write).rejects.toThrow() await expect(write).rejects.toThrow()
}) })
it('appends text to summary file', async () => { it('appends text to summary file', async () => {
await fs.promises.writeFile(testFilePath, '# ', {encoding: 'utf8'}) await fs.promises.writeFile(testFilePath, '# ', {encoding: 'utf8'})
await markdownSummary.addRaw(fixtures.text).write() await summary.addRaw(fixtures.text).write()
await assertSummary(`# ${fixtures.text}`) await assertSummary(`# ${fixtures.text}`)
}) })
it('overwrites text to summary file', async () => { it('overwrites text to summary file', async () => {
await fs.promises.writeFile(testFilePath, 'overwrite', {encoding: 'utf8'}) await fs.promises.writeFile(testFilePath, 'overwrite', {encoding: 'utf8'})
await markdownSummary.addRaw(fixtures.text).write({overwrite: true}) await summary.addRaw(fixtures.text).write({overwrite: true})
await assertSummary(fixtures.text) await assertSummary(fixtures.text)
}) })
it('appends text with EOL to summary file', async () => { it('appends text with EOL to summary file', async () => {
await fs.promises.writeFile(testFilePath, '# ', {encoding: 'utf8'}) await fs.promises.writeFile(testFilePath, '# ', {encoding: 'utf8'})
await markdownSummary.addRaw(fixtures.text, true).write() await summary.addRaw(fixtures.text, true).write()
await assertSummary(`# ${fixtures.text}${os.EOL}`) await assertSummary(`# ${fixtures.text}${os.EOL}`)
}) })
it('chains appends text to summary file', async () => { it('chains appends text to summary file', async () => {
await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'}) await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'})
await markdownSummary await summary
.addRaw(fixtures.text) .addRaw(fixtures.text)
.addRaw(fixtures.text) .addRaw(fixtures.text)
.addRaw(fixtures.text) .addRaw(fixtures.text)
@ -122,33 +124,33 @@ describe('@actions/core/src/markdown-summary', () => {
it('empties buffer after write', async () => { it('empties buffer after write', async () => {
await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'}) await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'})
await markdownSummary.addRaw(fixtures.text).write() await summary.addRaw(fixtures.text).write()
await assertSummary(fixtures.text) await assertSummary(fixtures.text)
expect(markdownSummary.isEmptyBuffer()).toBe(true) expect(summary.isEmptyBuffer()).toBe(true)
}) })
it('returns summary buffer as string', () => { it('returns summary buffer as string', () => {
markdownSummary.addRaw(fixtures.text) summary.addRaw(fixtures.text)
expect(markdownSummary.stringify()).toEqual(fixtures.text) expect(summary.stringify()).toEqual(fixtures.text)
}) })
it('return correct values for isEmptyBuffer', () => { it('return correct values for isEmptyBuffer', () => {
markdownSummary.addRaw(fixtures.text) summary.addRaw(fixtures.text)
expect(markdownSummary.isEmptyBuffer()).toBe(false) expect(summary.isEmptyBuffer()).toBe(false)
markdownSummary.emptyBuffer() summary.emptyBuffer()
expect(markdownSummary.isEmptyBuffer()).toBe(true) expect(summary.isEmptyBuffer()).toBe(true)
}) })
it('clears a buffer and summary file', async () => { it('clears a buffer and summary file', async () => {
await fs.promises.writeFile(testFilePath, 'content', {encoding: 'utf8'}) await fs.promises.writeFile(testFilePath, 'content', {encoding: 'utf8'})
await markdownSummary.clear() await summary.clear()
await assertSummary('') await assertSummary('')
expect(markdownSummary.isEmptyBuffer()).toBe(true) expect(summary.isEmptyBuffer()).toBe(true)
}) })
it('adds EOL', async () => { it('adds EOL', async () => {
await markdownSummary await summary
.addRaw(fixtures.text) .addRaw(fixtures.text)
.addEOL() .addEOL()
.write() .write()
@ -156,37 +158,37 @@ describe('@actions/core/src/markdown-summary', () => {
}) })
it('adds a code block without language', async () => { it('adds a code block without language', async () => {
await markdownSummary.addCodeBlock(fixtures.code).write() await summary.addCodeBlock(fixtures.code).write()
const expected = `<pre><code>func fork() {\n for {\n go fork()\n }\n}</code></pre>${os.EOL}` const expected = `<pre><code>func fork() {\n for {\n go fork()\n }\n}</code></pre>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('adds a code block with a language', async () => { it('adds a code block with a language', async () => {
await markdownSummary.addCodeBlock(fixtures.code, 'go').write() await summary.addCodeBlock(fixtures.code, 'go').write()
const expected = `<pre lang="go"><code>func fork() {\n for {\n go fork()\n }\n}</code></pre>${os.EOL}` const expected = `<pre lang="go"><code>func fork() {\n for {\n go fork()\n }\n}</code></pre>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('adds an unordered list', async () => { it('adds an unordered list', async () => {
await markdownSummary.addList(fixtures.list).write() await summary.addList(fixtures.list).write()
const expected = `<ul><li>foo</li><li>bar</li><li>baz</li><li>💣</li></ul>${os.EOL}` const expected = `<ul><li>foo</li><li>bar</li><li>baz</li><li>💣</li></ul>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('adds an ordered list', async () => { it('adds an ordered list', async () => {
await markdownSummary.addList(fixtures.list, true).write() await summary.addList(fixtures.list, true).write()
const expected = `<ol><li>foo</li><li>bar</li><li>baz</li><li>💣</li></ol>${os.EOL}` const expected = `<ol><li>foo</li><li>bar</li><li>baz</li><li>💣</li></ol>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('adds a table', async () => { it('adds a table', async () => {
await markdownSummary.addTable(fixtures.table).write() await summary.addTable(fixtures.table).write()
const expected = `<table><tr><th>foo</th><th>bar</th><th>baz</th><td rowspan="3">tall</td></tr><tr><td>one</td><td>two</td><td>three</td></tr><tr><td colspan="3">wide</td></tr></table>${os.EOL}` const expected = `<table><tr><th>foo</th><th>bar</th><th>baz</th><td rowspan="3">tall</td></tr><tr><td>one</td><td>two</td><td>three</td></tr><tr><td colspan="3">wide</td></tr></table>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('adds a details element', async () => { it('adds a details element', async () => {
await markdownSummary await summary
.addDetails(fixtures.details.label, fixtures.details.content) .addDetails(fixtures.details.label, fixtures.details.content)
.write() .write()
const expected = `<details><summary>open me</summary>🎉 surprise</details>${os.EOL}` const expected = `<details><summary>open me</summary>🎉 surprise</details>${os.EOL}`
@ -194,13 +196,13 @@ describe('@actions/core/src/markdown-summary', () => {
}) })
it('adds an image with alt text', async () => { it('adds an image with alt text', async () => {
await markdownSummary.addImage(fixtures.img.src, fixtures.img.alt).write() await summary.addImage(fixtures.img.src, fixtures.img.alt).write()
const expected = `<img src="https://github.com/actions.png" alt="actions logo">${os.EOL}` const expected = `<img src="https://github.com/actions.png" alt="actions logo">${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('adds an image with custom dimensions', async () => { it('adds an image with custom dimensions', async () => {
await markdownSummary await summary
.addImage(fixtures.img.src, fixtures.img.alt, fixtures.img.options) .addImage(fixtures.img.src, fixtures.img.alt, fixtures.img.options)
.write() .write()
const expected = `<img src="https://github.com/actions.png" alt="actions logo" width="32" height="32">${os.EOL}` const expected = `<img src="https://github.com/actions.png" alt="actions logo" width="32" height="32">${os.EOL}`
@ -208,7 +210,7 @@ describe('@actions/core/src/markdown-summary', () => {
}) })
it('adds an image with custom dimensions', async () => { it('adds an image with custom dimensions', async () => {
await markdownSummary await summary
.addImage(fixtures.img.src, fixtures.img.alt, fixtures.img.options) .addImage(fixtures.img.src, fixtures.img.alt, fixtures.img.options)
.write() .write()
const expected = `<img src="https://github.com/actions.png" alt="actions logo" width="32" height="32">${os.EOL}` const expected = `<img src="https://github.com/actions.png" alt="actions logo" width="32" height="32">${os.EOL}`
@ -217,21 +219,21 @@ describe('@actions/core/src/markdown-summary', () => {
it('adds headings h1...h6', async () => { it('adds headings h1...h6', async () => {
for (const i of [1, 2, 3, 4, 5, 6]) { for (const i of [1, 2, 3, 4, 5, 6]) {
markdownSummary.addHeading('heading', i) summary.addHeading('heading', i)
} }
await markdownSummary.write() await summary.write()
const expected = `<h1>heading</h1>${os.EOL}<h2>heading</h2>${os.EOL}<h3>heading</h3>${os.EOL}<h4>heading</h4>${os.EOL}<h5>heading</h5>${os.EOL}<h6>heading</h6>${os.EOL}` const expected = `<h1>heading</h1>${os.EOL}<h2>heading</h2>${os.EOL}<h3>heading</h3>${os.EOL}<h4>heading</h4>${os.EOL}<h5>heading</h5>${os.EOL}<h6>heading</h6>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('adds h1 if heading level not specified', async () => { it('adds h1 if heading level not specified', async () => {
await markdownSummary.addHeading('heading').write() await summary.addHeading('heading').write()
const expected = `<h1>heading</h1>${os.EOL}` const expected = `<h1>heading</h1>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('uses h1 if heading level is garbage or out of range', async () => { it('uses h1 if heading level is garbage or out of range', async () => {
await markdownSummary await summary
.addHeading('heading', 'foobar') .addHeading('heading', 'foobar')
.addHeading('heading', 1337) .addHeading('heading', 1337)
.addHeading('heading', -1) .addHeading('heading', -1)
@ -242,35 +244,31 @@ describe('@actions/core/src/markdown-summary', () => {
}) })
it('adds a separator', async () => { it('adds a separator', async () => {
await markdownSummary.addSeparator().write() await summary.addSeparator().write()
const expected = `<hr>${os.EOL}` const expected = `<hr>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('adds a break', async () => { it('adds a break', async () => {
await markdownSummary.addBreak().write() await summary.addBreak().write()
const expected = `<br>${os.EOL}` const expected = `<br>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('adds a quote', async () => { it('adds a quote', async () => {
await markdownSummary.addQuote(fixtures.quote.text).write() await summary.addQuote(fixtures.quote.text).write()
const expected = `<blockquote>Where the world builds software</blockquote>${os.EOL}` const expected = `<blockquote>Where the world builds software</blockquote>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('adds a quote with citation', async () => { it('adds a quote with citation', async () => {
await markdownSummary await summary.addQuote(fixtures.quote.text, fixtures.quote.cite).write()
.addQuote(fixtures.quote.text, fixtures.quote.cite)
.write()
const expected = `<blockquote cite="https://github.com/about">Where the world builds software</blockquote>${os.EOL}` const expected = `<blockquote cite="https://github.com/about">Where the world builds software</blockquote>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })
it('adds a link with href', async () => { it('adds a link with href', async () => {
await markdownSummary await summary.addLink(fixtures.link.text, fixtures.link.href).write()
.addLink(fixtures.link.text, fixtures.link.href)
.write()
const expected = `<a href="https://github.com/">GitHub</a>${os.EOL}` const expected = `<a href="https://github.com/">GitHub</a>${os.EOL}`
await assertSummary(expected) await assertSummary(expected)
}) })

View File

@ -361,6 +361,6 @@ export async function getIDToken(aud?: string): Promise<string> {
} }
/** /**
* Markdown summary exports * Summary exports
*/ */
export {markdownSummary} from './markdown-summary' export {summary} from './summary'

View File

@ -4,7 +4,7 @@ const {access, appendFile, writeFile} = promises
export const SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY' export const SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY'
export const SUMMARY_DOCS_URL = export const SUMMARY_DOCS_URL =
'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary' 'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary'
export type SummaryTableRow = (SummaryTableCell | string)[] export type SummaryTableRow = (SummaryTableCell | string)[]
@ -51,7 +51,7 @@ export interface SummaryWriteOptions {
overwrite?: boolean overwrite?: boolean
} }
class MarkdownSummary { class Summary {
private _buffer: string private _buffer: string
private _filePath?: string private _filePath?: string
@ -73,7 +73,7 @@ class MarkdownSummary {
const pathFromEnv = process.env[SUMMARY_ENV_VAR] const pathFromEnv = process.env[SUMMARY_ENV_VAR]
if (!pathFromEnv) { if (!pathFromEnv) {
throw new Error( throw new Error(
`Unable to find environment variable for $${SUMMARY_ENV_VAR}. Check if your runtime environment supports markdown summaries.` `Unable to find environment variable for $${SUMMARY_ENV_VAR}. Check if your runtime environment supports job summaries.`
) )
} }
@ -119,9 +119,9 @@ class MarkdownSummary {
* *
* @param {SummaryWriteOptions} [options] (optional) options for write operation * @param {SummaryWriteOptions} [options] (optional) options for write operation
* *
* @returns {Promise<MarkdownSummary>} markdown summary instance * @returns {Promise<Summary>} summary instance
*/ */
async write(options?: SummaryWriteOptions): Promise<MarkdownSummary> { async write(options?: SummaryWriteOptions): Promise<Summary> {
const overwrite = !!options?.overwrite const overwrite = !!options?.overwrite
const filePath = await this.filePath() const filePath = await this.filePath()
const writeFunc = overwrite ? writeFile : appendFile const writeFunc = overwrite ? writeFile : appendFile
@ -132,9 +132,9 @@ class MarkdownSummary {
/** /**
* Clears the summary buffer and wipes the summary file * Clears the summary buffer and wipes the summary file
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
async clear(): Promise<MarkdownSummary> { async clear(): Promise<Summary> {
return this.emptyBuffer().write({overwrite: true}) return this.emptyBuffer().write({overwrite: true})
} }
@ -159,9 +159,9 @@ class MarkdownSummary {
/** /**
* Resets the summary buffer without writing to summary file * Resets the summary buffer without writing to summary file
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
emptyBuffer(): MarkdownSummary { emptyBuffer(): Summary {
this._buffer = '' this._buffer = ''
return this return this
} }
@ -172,9 +172,9 @@ class MarkdownSummary {
* @param {string} text content to add * @param {string} text content to add
* @param {boolean} [addEOL=false] (optional) append an EOL to the raw text (default: false) * @param {boolean} [addEOL=false] (optional) append an EOL to the raw text (default: false)
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addRaw(text: string, addEOL = false): MarkdownSummary { addRaw(text: string, addEOL = false): Summary {
this._buffer += text this._buffer += text
return addEOL ? this.addEOL() : this return addEOL ? this.addEOL() : this
} }
@ -182,9 +182,9 @@ class MarkdownSummary {
/** /**
* Adds the operating system-specific end-of-line marker to the buffer * Adds the operating system-specific end-of-line marker to the buffer
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addEOL(): MarkdownSummary { addEOL(): Summary {
return this.addRaw(EOL) return this.addRaw(EOL)
} }
@ -194,9 +194,9 @@ class MarkdownSummary {
* @param {string} code content to render within fenced code block * @param {string} code content to render within fenced code block
* @param {string} lang (optional) language to syntax highlight code * @param {string} lang (optional) language to syntax highlight code
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addCodeBlock(code: string, lang?: string): MarkdownSummary { addCodeBlock(code: string, lang?: string): Summary {
const attrs = { const attrs = {
...(lang && {lang}) ...(lang && {lang})
} }
@ -210,9 +210,9 @@ class MarkdownSummary {
* @param {string[]} items list of items to render * @param {string[]} items list of items to render
* @param {boolean} [ordered=false] (optional) if the rendered list should be ordered or not (default: false) * @param {boolean} [ordered=false] (optional) if the rendered list should be ordered or not (default: false)
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addList(items: string[], ordered = false): MarkdownSummary { addList(items: string[], ordered = false): Summary {
const tag = ordered ? 'ol' : 'ul' const tag = ordered ? 'ol' : 'ul'
const listItems = items.map(item => this.wrap('li', item)).join('') const listItems = items.map(item => this.wrap('li', item)).join('')
const element = this.wrap(tag, listItems) const element = this.wrap(tag, listItems)
@ -224,9 +224,9 @@ class MarkdownSummary {
* *
* @param {SummaryTableCell[]} rows table rows * @param {SummaryTableCell[]} rows table rows
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addTable(rows: SummaryTableRow[]): MarkdownSummary { addTable(rows: SummaryTableRow[]): Summary {
const tableBody = rows const tableBody = rows
.map(row => { .map(row => {
const cells = row const cells = row
@ -260,9 +260,9 @@ class MarkdownSummary {
* @param {string} label text for the closed state * @param {string} label text for the closed state
* @param {string} content collapsable content * @param {string} content collapsable content
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addDetails(label: string, content: string): MarkdownSummary { addDetails(label: string, content: string): Summary {
const element = this.wrap('details', this.wrap('summary', label) + content) const element = this.wrap('details', this.wrap('summary', label) + content)
return this.addRaw(element).addEOL() return this.addRaw(element).addEOL()
} }
@ -274,13 +274,9 @@ class MarkdownSummary {
* @param {string} alt text description of the image * @param {string} alt text description of the image
* @param {SummaryImageOptions} options (optional) addition image attributes * @param {SummaryImageOptions} options (optional) addition image attributes
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addImage( addImage(src: string, alt: string, options?: SummaryImageOptions): Summary {
src: string,
alt: string,
options?: SummaryImageOptions
): MarkdownSummary {
const {width, height} = options || {} const {width, height} = options || {}
const attrs = { const attrs = {
...(width && {width}), ...(width && {width}),
@ -297,9 +293,9 @@ class MarkdownSummary {
* @param {string} text heading text * @param {string} text heading text
* @param {number | string} [level=1] (optional) the heading level, default: 1 * @param {number | string} [level=1] (optional) the heading level, default: 1
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addHeading(text: string, level?: number | string): MarkdownSummary { addHeading(text: string, level?: number | string): Summary {
const tag = `h${level}` const tag = `h${level}`
const allowedTag = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag) const allowedTag = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)
? tag ? tag
@ -311,9 +307,9 @@ class MarkdownSummary {
/** /**
* Adds an HTML thematic break (<hr>) to the summary buffer * Adds an HTML thematic break (<hr>) to the summary buffer
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addSeparator(): MarkdownSummary { addSeparator(): Summary {
const element = this.wrap('hr', null) const element = this.wrap('hr', null)
return this.addRaw(element).addEOL() return this.addRaw(element).addEOL()
} }
@ -321,9 +317,9 @@ class MarkdownSummary {
/** /**
* Adds an HTML line break (<br>) to the summary buffer * Adds an HTML line break (<br>) to the summary buffer
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addBreak(): MarkdownSummary { addBreak(): Summary {
const element = this.wrap('br', null) const element = this.wrap('br', null)
return this.addRaw(element).addEOL() return this.addRaw(element).addEOL()
} }
@ -334,9 +330,9 @@ class MarkdownSummary {
* @param {string} text quote text * @param {string} text quote text
* @param {string} cite (optional) citation url * @param {string} cite (optional) citation url
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addQuote(text: string, cite?: string): MarkdownSummary { addQuote(text: string, cite?: string): Summary {
const attrs = { const attrs = {
...(cite && {cite}) ...(cite && {cite})
} }
@ -350,13 +346,13 @@ class MarkdownSummary {
* @param {string} text link text/content * @param {string} text link text/content
* @param {string} href hyperlink * @param {string} href hyperlink
* *
* @returns {MarkdownSummary} markdown summary instance * @returns {Summary} summary instance
*/ */
addLink(text: string, href: string): MarkdownSummary { addLink(text: string, href: string): Summary {
const element = this.wrap('a', text, {href}) const element = this.wrap('a', text, {href})
return this.addRaw(element).addEOL() return this.addRaw(element).addEOL()
} }
} }
// singleton export // singleton export
export const markdownSummary = new MarkdownSummary() export const summary = new Summary()