Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/core/bin/docs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict'

const url = product => `https://microlink.io/docs/sdk/methods/${product}.md`

const load = async (product, fetchFn = fetch) => {
const href = url(product)
const res = await fetchFn(href, { signal: AbortSignal.timeout(10_000) })
if (!res.ok) throw new Error(`Failed to fetch ${href} (${res.status})`)
return res.text()
}

module.exports = { load, url }
17 changes: 11 additions & 6 deletions packages/core/bin/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ const commandList = Object.entries(COMMANDS)
const global = `Usage
${cmd('<url> [options]')}
${cmd('<product> <url|query> [options]')}
${cmd('<product> docs')}
${cmd('help')}
${cmd('login')}
${cmd('logout')}
Expand All @@ -316,6 +317,7 @@ ${rows(CLI)}

Examples
${cmd('login', 'save an API key from your account')}
${cmd('markdown docs', 'print the markdown docs page')}
${cmd('https://example.com', 'unified metadata (default)')}
${cmd(
'https://example.com --trace',
Expand Down Expand Up @@ -348,21 +350,24 @@ ${cmd(
`

const render = (name, product) => {
const usage = []
.concat(product.usage)
.map(line => cmd(line))
.join('\n')
const usageLines = [].concat(product.usage)
const examples = [...(product.examples ?? [])]
if (PRODUCTS[name]) {
usageLines.push(`${name} docs`)
examples.push([`${name} docs`, 'print the docs page'])
}
const usage = usageLines.map(line => cmd(line)).join('\n')
const cli = product.cli ?? CLI
const options = [...product.flags, ...cli]
const parts = ['Usage', usage, '', gray(product.desc)]
if (options.length > 0) parts.push('', 'Options', rows(options))
if (product.browser) parts.push('', 'Browser', rows(BROWSER))
if (product.note) parts.push('', gray(product.note))
if (product.examples) {
if (examples.length > 0) {
parts.push(
'',
'Examples',
...product.examples.map(([rest, comment]) => cmd(rest, comment))
...examples.map(([rest, comment]) => cmd(rest, comment))
)
}
return parts.join('\n') + '\n'
Expand Down
15 changes: 15 additions & 0 deletions packages/core/bin/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const spinner = require('./spinner')
const parseArgv = require('./argv')
const helpText = require('./help')
const { asUrl } = require('./url')
const docs = require('./docs')
const create = require('../src')

const run = async (argvInput, host) => {
Expand Down Expand Up @@ -86,6 +87,20 @@ const run = async (argvInput, host) => {
}

if (help || !target) return showHelp(command)

if (target === 'docs') {
try {
writeLine(
stdout,
(await docs.load(command, host.fetch ?? fetch)).trimEnd()
)
return finish(0)
} catch (error) {
writeLine(stderr, error.message)
return finish(1)
}
}

if (command !== 'search') target = asUrl(target) ?? target

if (isTrace && (command === 'search' || command === 'function')) {
Expand Down
21 changes: 21 additions & 0 deletions packages/core/test/cli.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ test('prints help with no arguments', async t => {
t.true(stdout.includes('--endpoint'))
t.true(stdout.includes('login'))
t.true(stdout.includes('logout'))
t.true(stdout.includes('<product> docs'))
})

test('help command matches --help', async t => {
Expand Down Expand Up @@ -50,6 +51,12 @@ test('prints command help for logout', async t => {
t.true(stdout.includes('Remove the saved API key'))
})

test('product help includes the docs usage', async t => {
const { stdout } = await $('node', [bin, 'markdown', '--help'])
t.true(stdout.includes('markdown docs'))
t.true(stdout.includes('print the docs page'))
})

test('prints command help for a product with no url', async t => {
const { stdout } = await $('node', [bin, 'metadata'])
t.true(stdout.includes('metadata <url>'))
Expand Down Expand Up @@ -509,6 +516,20 @@ test('run reports unknown commands through the host', async t => {
t.true(host.stderrText().includes('Unknown command'))
})

test('run <product> docs writes the fetched markdown through the host', async t => {
const host = memoryHost({
fetch: url => {
t.is(url, 'https://microlink.io/docs/sdk/methods/markdown.md')
return Promise.resolve({
ok: true,
text: () => Promise.resolve('# markdown\n')
})
}
})
t.is(await run(['markdown', 'docs'], host), 0)
t.is(host.stdoutText().trim(), '# markdown')
})

test('run reports missing --file through the host', async t => {
const host = memoryHost()
t.is(await run(['function', 'https://example.com'], host), 1)
Expand Down
28 changes: 28 additions & 0 deletions packages/core/test/docs.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createRequire } from 'module'
import test from 'ava'

const require = createRequire(import.meta.url)
const { load, url } = require('../bin/docs')

test('points at the SDK method markdown file', t => {
t.is(url('markdown'), 'https://microlink.io/docs/sdk/methods/markdown.md')
})

test('load fetches the markdown file', async t => {
const text = await load('markdown', (href, opts) => {
t.is(href, url('markdown'))
t.true(opts.signal instanceof AbortSignal)
return Promise.resolve({
ok: true,
text: () => Promise.resolve('# markdown\n')
})
})
t.is(text, '# markdown\n')
})

test('load throws when the page is missing', async t => {
const error = await t.throwsAsync(() =>
load('markdown', () => Promise.resolve({ ok: false, status: 404 }))
)
t.true(error.message.includes('404'))
})