Skip to content

Commit 416245b

Browse files
author
zoey
authored
refactor: avoid falsy values and try/catch (#1)
1 parent f049f92 commit 416245b

10 files changed

Lines changed: 552 additions & 308 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ vite.config.ts.timestamp-*
6666

6767
# bun
6868
/.bun/
69+
/dist/
6970

7071
# Coding agents
7172
CLAUDE.md
72-
.claude/
73+
.claude/

bun.lock

Lines changed: 151 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cli/index.ts

Lines changed: 53 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,83 +3,68 @@
33

44
import { program } from 'commander';
55
import chalk from 'chalk';
6+
import { tools, getDocs, getSourcePath } from '../tools';
67
import { TidewaveExtractor } from '../index';
8+
import { isExtractError, isResolveError } from '../core';
9+
10+
import { name, version } from '../../package.json';
711

812
// CLI Interface
913
program
10-
.name('tidewave')
14+
.name(name)
1115
.description('Universal documentation and source extraction tool for TypeScript and JavaScript')
12-
.version('0.1.0');
16+
.version(version);
1317

14-
program
15-
.command('docs')
16-
.description('Extract documentation for a symbol')
17-
.argument(
18-
'<module-path>',
19-
'Module path formats:\n' +
20-
' - module:symbol - Extract a top-level symbol\n' +
21-
' - module:Class#method - Extract an instance method\n' +
22-
' - module:Class.method - Extract a static method\n' +
23-
' - node:Class#method - Extract a global/builtin instance method\n' +
24-
' - node:Class.method - Extract a global/builtin static method\n' +
25-
'\n' +
26-
'Examples:\n' +
27-
' - src/types.ts:SymbolInfo\n' +
28-
' - ./utils:parseConfig\n' +
29-
' - lodash:isEmpty\n' +
30-
' - react:Component#render\n' +
31-
' - Math:Math.max',
32-
)
33-
.option('-c, --config <path>', 'Path to tsconfig.json')
34-
.option('-j, --json', 'Output as JSON')
35-
.action(async (modulePath: string, options) => {
36-
try {
37-
const docs = await TidewaveExtractor.extractDocs(modulePath, {
38-
tsConfigPath: options.config,
39-
});
18+
async function handleGetDocs(
19+
modulePath: string,
20+
options: { config?: string; json?: boolean },
21+
): Promise<void> {
22+
const docsResult = await getDocs(modulePath, { config: options.config });
23+
24+
if (isExtractError(docsResult)) {
25+
console.error(chalk.red(`Error: ${docsResult.error.message}`));
26+
process.exit(1);
27+
}
28+
29+
if (options.json) {
30+
console.log(JSON.stringify(docsResult, null, 2));
31+
} else {
32+
console.log(TidewaveExtractor.formatOutput(docsResult));
33+
}
34+
}
4035

41-
if (docs) {
42-
if (options.json) {
43-
console.log(JSON.stringify(docs, null, 2));
44-
} else {
45-
console.log(TidewaveExtractor.formatOutput(docs));
46-
}
47-
} else {
48-
process.exit(1);
49-
}
50-
} catch (error) {
51-
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
52-
process.exit(1);
53-
}
54-
});
36+
async function handleGetSourcePath(
37+
moduleName: string,
38+
options: { config?: string },
39+
): Promise<void> {
40+
const sourceResult = await getSourcePath(moduleName, { config: options.config });
41+
42+
if (isResolveError(sourceResult)) {
43+
console.error(chalk.red(`Error: ${sourceResult.error.message}`));
44+
process.exit(1);
45+
}
46+
47+
console.log(sourceResult.path);
48+
}
49+
const {
50+
docs: { cli: docsCli },
51+
source: { cli: sourceCli },
52+
} = tools;
53+
54+
program
55+
.command(docsCli.command)
56+
.description(docsCli.description)
57+
.argument(docsCli.argument, docsCli.argumentDescription)
58+
.option(docsCli.options.config!.flag, docsCli.options.config!.desc)
59+
.option(docsCli.options.json!.flag, docsCli.options.json!.desc)
60+
.action(handleGetDocs);
5561

5662
program
57-
.command('source')
58-
.description('Get the source file path for a module')
59-
.argument(
60-
'<module>',
61-
'Module name to resolve:\n' +
62-
' - Local files: src/utils, ./types.ts, ../config\n' +
63-
' - Dependencies: lodash, react, @types/node\n' +
64-
' - Relative paths: ./src/components/Button',
65-
)
66-
.option('-c, --config <path>', 'Path to tsconfig.json')
67-
.action(async (moduleName: string, options) => {
68-
try {
69-
const sourcePath = await TidewaveExtractor.getSourcePath(moduleName, {
70-
tsConfigPath: options.config,
71-
});
63+
.command(sourceCli.command)
64+
.description(sourceCli.description)
65+
.argument(sourceCli.argument, sourceCli.argumentDescription)
66+
.option(sourceCli.options.config!.flag, sourceCli.options.config!.desc)
7267

73-
if (sourcePath) {
74-
console.log(sourcePath);
75-
} else {
76-
process.exit(1);
77-
}
78-
} catch (error) {
79-
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
80-
process.exit(1);
81-
}
82-
});
68+
.action(handleGetSourcePath);
8369

84-
// Entry point
8570
program.parse(process.argv);

src/core.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ export interface ResolvedModule {
1818
readonly content?: string;
1919
}
2020

21+
// Internal type for module resolution with TypeScript program
22+
export interface InternalResolvedModule {
23+
readonly sourceFile: ts.SourceFile;
24+
readonly program: ts.Program;
25+
}
26+
2127
export interface ExtractionRequest {
2228
readonly module: string;
2329
readonly symbol: string;
@@ -65,13 +71,16 @@ export interface ExtractError {
6571

6672
export type ResolveResult = ResolvedModule | ResolveError;
6773
export type ExtractResult = SymbolInfo | ExtractError;
74+
export type InternalResolveResult = InternalResolvedModule | ResolveError;
6875

6976
export function isError(result: ResolveResult | ExtractResult): boolean {
7077
return result != null && 'success' in result && result.success === false;
7178
}
7279

73-
export function isResolveError(result: ResolveResult): result is ResolveError {
74-
return isError(result);
80+
export function isResolveError(
81+
result: ResolveResult | InternalResolveResult,
82+
): result is ResolveError {
83+
return result != null && 'success' in result && result.success === false;
7584
}
7685

7786
export function isExtractError(result: ExtractResult): result is ExtractError {

0 commit comments

Comments
 (0)