diff --git a/deno.json b/deno.json index 6e8204a..79c121b 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@michaelmass/stodo", - "version": "0.1.14", + "version": "0.1.15", "lock": false, "exports": { ".": "./src/mod.ts", diff --git a/src/cli.ts b/src/cli.ts index d3f3e4a..f5d4214 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -5,92 +5,8 @@ * */ import data from '../deno.json' with { type: 'json' } -import { Command, EnumType } from './deps.ts' -import { formats } from './format.ts' -import { formatResults } from './format.ts' -import { runJq } from './jq.ts' -import { type PriorityMarker, type SearchResult, parseSearchResults, search } from './todo.ts' +import { searchCommand } from './commands/search.ts' +import { doctorCommand } from './commands/doctor.ts' +import { Command } from './deps.ts' -await new Command() - .name('stodo') - .version(data.version) - .description('Command line to list all todos in a folder') - .command('search', 'search the for todos in the folder') - .type('format', new EnumType(formats)) - .option('-d, --dir ', 'Directory to search for todos', { default: '.' }) - .option('-f, --format ', 'Format to output the results in', { default: 'json' }) - .option('-t, --tags ', 'Tags to search for', { collect: true }) - .option('-g, --globs ', 'Globs to include or exclude files', { collect: true }) - .option('-c, --comments ', 'Comments string to look for', { collect: true }) - .option('--jq ', 'JQ query to filter search results') - .option('-p, --priorities ', 'Priority markers to use', { - collect: true, - value: (value: string, previous: Array = []): Array => { - const [name, marker, priority] = value.split(':') - return [...previous, { name, marker, value: Number.parseInt(priority) }] - }, - }) - .option('-e, --exit-code', 'Exit with a non-zero code if there are todos found', { default: false }) - .option('--git-blame', 'Run git blame on the todos found', { default: true }) - .action(async options => { - const results = await search(options) - - const { output, count } = await getOutput(results, options) - - // biome-ignore lint/suspicious/noConsoleLog: This is the output of the command - console.log(output) - - if (options.exitCode && count > 0) { - Deno.exit(1) - } - }) - .parse(Deno.args) - -async function getOutput(results: SearchResult[], { format, jq }: { format: (typeof formats)[number]; jq?: string }): Promise<{ output: string; count: number }> { - if (jq) { - const jqOutput = await runJq({ filter: jq, json: results }) - - if (format === 'json') { - const count = countJqResults(jqOutput) - return { output: jqOutput, count } - } - - const jqResults = parseSearchResults(JSON.parse(jqOutput)) - - return { output: formatResults(jqResults, format), count: jqResults.length } - } - - const output = formatResults(results, format) - - return { output, count: results.length } -} - -function countJqResults(results: string): number { - const data: unknown = JSON.parse(results) - - if (Array.isArray(data)) { - return data.length - } - - if (typeof data === 'object') { - if (data === null) { - return 0 - } - - return Object.keys(data).length - } - - if (!data) { - return 0 - } - - if (typeof data === 'number') { - return data - } - - if (typeof data === 'string') { - return data.length - } - - return 0 -} +await new Command().name('stodo').version(data.version).description('Command line to list all todos in a folder').command('doctor', doctorCommand).command('search', searchCommand).parse(Deno.args) diff --git a/src/commands/doctor.ts b/src/commands/doctor.ts new file mode 100644 index 0000000..3233b2c --- /dev/null +++ b/src/commands/doctor.ts @@ -0,0 +1,3 @@ +import { Command } from '../deps.ts' + +export const doctorCommand = new Command().description('Ensure all required dependencies are installed').action(async () => {}) diff --git a/src/commands/search.ts b/src/commands/search.ts new file mode 100644 index 0000000..81d53b5 --- /dev/null +++ b/src/commands/search.ts @@ -0,0 +1,85 @@ +import { Command, EnumType } from '../deps.ts' +import { formats } from '../format.ts' +import { formatResults } from '../format.ts' +import { runJq } from '../jq.ts' +import { type PriorityMarker, type SearchResult, parseSearchResults, search } from '../todo.ts' + +export const searchCommand = new Command() + .description('Search for todos in the folder') + .type('format', new EnumType(formats)) + .option('-d, --dir ', 'Directory to search for todos', { default: '.' }) + .option('-f, --format ', 'Format to output the results in', { default: 'json' }) + .option('-t, --tags ', 'Tags to search for', { collect: true }) + .option('-g, --globs ', 'Globs to include or exclude files', { collect: true }) + .option('-c, --comments ', 'Comments string to look for', { collect: true }) + .option('--jq ', 'JQ query to filter search results') + .option('-p, --priorities ', 'Priority markers to use', { + collect: true, + value: (value: string, previous: Array = []): Array => { + const [name, marker, priority] = value.split(':') + return [...previous, { name, marker, value: Number.parseInt(priority) }] + }, + }) + .option('-e, --exit-code', 'Exit with a non-zero code if there are todos found', { default: false }) + .option('--git-blame', 'Run git blame on the todos found', { default: true }) + .action(async options => { + const results = await search(options) + + const { output, count } = await getOutput(results, options) + + // biome-ignore lint/suspicious/noConsoleLog: This is the output of the command + console.log(output) + + if (options.exitCode && count > 0) { + Deno.exit(1) + } + }) + +async function getOutput(results: SearchResult[], { format, jq }: { format: (typeof formats)[number]; jq?: string }): Promise<{ output: string; count: number }> { + if (jq) { + const jqOutput = await runJq({ filter: jq, json: results }) + + if (format === 'json') { + const count = countJqResults(jqOutput) + return { output: jqOutput, count } + } + + const jqResults = parseSearchResults(JSON.parse(jqOutput)) + + return { output: formatResults(jqResults, format), count: jqResults.length } + } + + const output = formatResults(results, format) + + return { output, count: results.length } +} + +function countJqResults(results: string): number { + const data: unknown = JSON.parse(results) + + if (Array.isArray(data)) { + return data.length + } + + if (typeof data === 'object') { + if (data === null) { + return 0 + } + + return Object.keys(data).length + } + + if (!data) { + return 0 + } + + if (typeof data === 'number') { + return data + } + + if (typeof data === 'string') { + return data.length + } + + return 0 +}