Skip to content

Commit 849cd8a

Browse files
committed
ts.ts: finish parity for now
- adds comments - consistent conventions - help parity with bash
1 parent 87f7881 commit 849cd8a

16 files changed

Lines changed: 805 additions & 343 deletions

commands/ai-sync

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,26 @@ import {
44
HelpError,
55
exitWithError,
66
writeStdoutPlain,
7+
heredoc,
78
asString,
89
asError,
910
} from '../sources/ts.ts'
1011

1112
// Custom error for this command with help text
1213
class UsageError extends HelpError {
13-
override help = [
14-
'USAGE:',
15-
'`ai-sync --import-typingmind-json-export=<path> --target=anythingllm`',
16-
'',
17-
'OPTIONS:',
18-
'--import-typingmind-json-export=<typingmind-json-export>',
19-
' Path to the TypingMind export saved as .json file.',
20-
'--target=<target>',
21-
' Import target (currently: AnythingLLM)',
22-
'',
23-
'EXAMPLES:',
24-
'`ai-sync --import-typingmind-json-export="$HOME/Downloads/typingmind.json" --target=anythingllm`',
25-
].join('\n')
14+
override help = heredoc`
15+
USAGE:
16+
\`ai-sync --import-typingmind-json-export=<path> --target=anythingllm\`
17+
18+
OPTIONS:
19+
--import-typingmind-json-export=<typingmind-json-export>
20+
Path to the TypingMind export saved as .json file.
21+
--target=<target>
22+
Import target (currently: AnythingLLM)
23+
24+
EXAMPLES:
25+
\`ai-sync --import-typingmind-json-export="$HOME/Downloads/typingmind.json" --target=anythingllm\`
26+
`
2627
}
2728

2829
// Validate target

commands/brew-installed.ts

Lines changed: 67 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,81 @@
11
#!/usr/bin/env -S eval-wsl deno run --quiet --no-config --no-lock --no-npm --no-remote --cached-only
22
// deno-lint-ignore-file no-explicit-any
33

4-
// parse stdin
5-
const json = await new Response(Deno.stdin.readable).json()
6-
7-
// prepare result
8-
const names = new Set<string>()
9-
10-
// type
11-
const type: 'cask' | 'formula' | 'tap' | '' = Deno.args.includes('--type=cask')
12-
? 'cask'
13-
: Deno.args.includes('--type=formula')
14-
? 'formula'
15-
: Deno.args.includes('--type=tap')
16-
? 'tap'
17-
: ''
18-
19-
// add taps if desired
20-
if (['tap'].includes(type)) {
21-
// all taps are by request
22-
const taps = json || []
23-
for (const tap of taps.filter((i: any) => i.installed)) {
24-
names.add(tap.name)
25-
}
4+
import { heredoc, HelpError, exitWithError, wantsHelp } from '../sources/ts.ts'
5+
6+
class UsageError extends HelpError {
7+
override help = heredoc`
8+
USAGE:
9+
\`brew-installed.ts [--type=<cask|formula|tap>] [--requested] <brew.json\`
10+
`
2611
}
2712

28-
// add casks if desired
29-
if (['', 'cask'].includes(type)) {
30-
// all casks are by request
31-
const casks = json.casks || []
32-
for (const cask of casks.filter((i: any) => i.installed)) {
33-
names.add(cask.full_token)
13+
async function main(...args: string[]) {
14+
// parse stdin
15+
const json = await new Response(Deno.stdin.readable).json()
16+
17+
// prepare result
18+
const names = new Set<string>()
19+
20+
// type
21+
const type: 'cask' | 'formula' | 'tap' | '' = args.includes('--type=cask')
22+
? 'cask'
23+
: args.includes('--type=formula')
24+
? 'formula'
25+
: args.includes('--type=tap')
26+
? 'tap'
27+
: ''
28+
29+
// add taps if desired
30+
if (['tap'].includes(type)) {
31+
// all taps are by request
32+
const taps = json || []
33+
for (const tap of taps.filter((i: any) => i.installed)) {
34+
names.add(tap.name)
35+
}
3436
}
35-
}
3637

37-
// add formulas if desired
38-
if (['', 'formula'].includes(type)) {
39-
// formulas could be by request, or by dependency
40-
const formulae = json.formulae || []
41-
if (Deno.args.includes('--requested')) {
42-
// only requested formula
43-
for (const formula of formulae) {
44-
if (formula.installed.find((i: any) => i.installed_on_request)) {
38+
// add casks if desired
39+
if (['', 'cask'].includes(type)) {
40+
// all casks are by request
41+
const casks = json.casks || []
42+
for (const cask of casks.filter((i: any) => i.installed)) {
43+
names.add(cask.full_token)
44+
}
45+
}
46+
47+
// add formulas if desired
48+
if (['', 'formula'].includes(type)) {
49+
// formulas could be by request, or by dependency
50+
const formulae = json.formulae || []
51+
if (args.includes('--requested')) {
52+
// only requested formula
53+
for (const formula of formulae) {
54+
if (formula.installed.find((i: any) => i.installed_on_request)) {
55+
names.add(formula.full_name)
56+
}
57+
}
58+
} else {
59+
// all formula
60+
for (const formula of formulae.filter((i: any) => i.installed)) {
4561
names.add(formula.full_name)
4662
}
4763
}
48-
} else {
49-
// all formula
50-
for (const formula of formulae.filter((i: any) => i.installed)) {
51-
names.add(formula.full_name)
52-
}
64+
}
65+
66+
// output result
67+
if (names.size) {
68+
await Deno.stdout.write(
69+
new TextEncoder().encode(Array.from(names).sort().concat('').join('\n')),
70+
)
5371
}
5472
}
5573

56-
// output result
57-
if (names.size) {
58-
await Deno.stdout.write(
59-
new TextEncoder().encode(Array.from(names).sort().concat('').join('\n')),
60-
)
74+
try {
75+
if (wantsHelp(Deno.args)) {
76+
throw new UsageError()
77+
}
78+
await main(...Deno.args)
79+
} catch (error) {
80+
await exitWithError(error)
6181
}

commands/echo-help.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,34 @@ import {
55
exitWithError,
66
readStdinWhole,
77
exec,
8+
heredoc,
9+
wantsHelp,
10+
wantsTests,
811
} from '../sources/ts.ts'
912

1013
class UsageError extends HelpError {
11-
override help = [
12-
'USAGE:',
13-
'`echo-help.ts --test`',
14-
'`echo-help.ts --help`',
15-
'`echo-help.ts [...<styled error messages>] < template.txt`',
16-
'',
17-
'NOTE:',
18-
'This is a test implementation only. Use the bash version `echo-help` for production.',
19-
].join('\n')
14+
override help = heredoc`
15+
USAGE:
16+
\`echo-help.ts --test\`
17+
\`echo-help.ts --help\`
18+
\`echo-help.ts [...<styled error messages>] <template.txt\`
19+
20+
NOTE:
21+
This is a test implementation only. Use the bash version \`echo-help\` for production.
22+
`
2023
}
2124

2225
// Execute
2326
async function main(...args: string[]) {
2427
const help = await readStdinWhole()
25-
throw new HelpError({help, code: 0}, ...args)
28+
throw new HelpError({ help, code: 0 }, ...args)
2629
}
2730

2831
// invoke command or tests
2932
try {
30-
if (Deno.args.join('') == '--help' ) {
33+
if (wantsHelp(Deno.args)) {
3134
throw new UsageError()
32-
} else if (Deno.args.join('') == '--test' ) {
35+
} else if (wantsTests(Deno.args)) {
3336
await exec(['eval-tester', '--fixture=echo-help', '--', 'echo-help.ts'])
3437
} else {
3538
await main(...Deno.args)

commands/echo-html-coder.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,30 @@
11
#!/usr/bin/env -S eval-wsl deno run --quiet --no-config --no-lock --no-npm
2+
3+
import { heredoc, HelpError, exitWithError, wantsHelp } from '../sources/ts.ts'
24
import { Html5Entities } from 'https://deno.land/x/html_entities@v1.0/mod.js'
3-
const coder =
4-
Deno.args[0] === 'decode' ? Html5Entities.decode : Html5Entities.encode
5-
const url = Deno.args[1]
6-
console.log(coder(url))
5+
6+
class UsageError extends HelpError {
7+
override help = heredoc`
8+
USAGE:
9+
\`echo-html-coder.ts <encode|decode> <text>\`
10+
`
11+
}
12+
13+
function main(...args: string[]) {
14+
if (args.length < 2) {
15+
throw new UsageError('--help=Expected <encode|decode> and <text>.')
16+
}
17+
const coder =
18+
args[0] === 'decode' ? Html5Entities.decode : Html5Entities.encode
19+
const value = args[1]
20+
console.log(coder(value))
21+
}
22+
23+
try {
24+
if (wantsHelp(Deno.args)) {
25+
throw new UsageError()
26+
}
27+
main(...Deno.args)
28+
} catch (error) {
29+
await exitWithError(error)
30+
}

commands/echo-json.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#!/usr/bin/env -S eval-wsl deno run --quiet --no-config --no-lock --no-npm --no-remote --cached-only
2+
// deno-lint-ignore-file no-unreachable
23

3-
import { styleText } from 'node:util'
44
import {
55
HelpError,
66
exitWithError,
77
writeStdoutStringify,
88
writeStdoutPlain,
99
writeStdoutPretty,
10+
heredoc,
11+
wantsHelp,
1012
asString,
1113
asError,
1214
assertFactory,
@@ -18,11 +20,11 @@ const { values: actionValues, as: asAction } = assertFactory(
1820
)
1921

2022
class UsageError extends HelpError {
21-
override help = [
22-
'USAGE:',
23-
'`echo-json.ts <make> [--] ...[<key> <value>]`',
24-
`\`echo-json.ts <${actionValues.join('|')}> [--] ...<input>\``,
25-
].join('\n')
23+
override help = heredoc`
24+
USAGE:
25+
\`echo-json.ts <make> [--] ...[<key> <value>]\`
26+
\`echo-json.ts <${actionValues.join('|')}> [--] ...<input>\`
27+
`
2628
}
2729

2830
// Parsing
@@ -52,7 +54,7 @@ function parse(input: string): {
5254

5355
// Execute
5456
// <action> [...options] ...<input>
55-
async function main(...args: string[]) {
57+
function main(...args: string[]) {
5658
// parse <action>
5759
if (args.length === 0) {
5860
throw new UsageError(`--help=No <action> was provided.`)
@@ -158,7 +160,10 @@ async function main(...args: string[]) {
158160
}
159161

160162
try {
163+
if (wantsHelp(Deno.args)) {
164+
throw new UsageError()
165+
}
161166
await main(...Deno.args)
162167
} catch (error) {
163-
exitWithError(error)
168+
await exitWithError(error)
164169
}

commands/echo-math.ts

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,61 @@
11
#!/usr/bin/env -S eval-wsl deno run --quiet --no-config --no-lock --no-npm --no-remote --cached-only
2-
const precision = Number(Deno.args[0])
3-
const formula = Deno.args[1]
4-
const result = Number(eval(formula))
5-
const output = result.toFixed(precision)
6-
console.log(output)
2+
3+
import { heredoc, HelpError, exitWithError, wantsHelp } from '../sources/ts.ts'
4+
5+
class UsageError extends HelpError {
6+
override help = heredoc`
7+
USAGE:
8+
\`echo-math.ts <precision> <formula>\`
9+
10+
EXAMPLE:
11+
\`echo-math.ts 2 "1/3"\`
12+
`
13+
}
14+
15+
function assertFormula(value: unknown): asserts value is string {
16+
if (typeof value !== 'string' || value.trim() === '') {
17+
throw new UsageError('--help=<formula> must be a non-empty string.')
18+
}
19+
if (!/^[0-9+\-*/%().\s]+$/.test(value)) {
20+
throw new UsageError(
21+
'--help=The <formula> may only contain numbers, spaces, and math operators: \`+ - * / % ( ) .\`',
22+
)
23+
}
24+
}
25+
26+
function assertPrecision(value: number): asserts value is number {
27+
if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0) {
28+
throw new UsageError('--help=<precision> must be a non-negative integer.')
29+
}
30+
}
31+
32+
function assertEvaluatedNumber(value: number): asserts value is number {
33+
if (Number.isNaN(value)) {
34+
throw new UsageError('--help=<formula> must evaluate to a number.')
35+
}
36+
}
37+
38+
function main(...args: string[]) {
39+
if (args.length < 2) {
40+
throw new UsageError('--help=Expected <precision> and <formula>.')
41+
}
42+
const precisionInput: unknown = args[0]
43+
const formulaInput: unknown = args[1]
44+
assertFormula(formulaInput)
45+
const precision = Number(precisionInput)
46+
assertPrecision(precision)
47+
const formula = formulaInput
48+
const result = Number(eval(formula))
49+
assertEvaluatedNumber(result)
50+
const output = result.toFixed(precision)
51+
console.log(output)
52+
}
53+
54+
try {
55+
if (wantsHelp(Deno.args)) {
56+
throw new UsageError()
57+
}
58+
main(...Deno.args)
59+
} catch (error) {
60+
await exitWithError(error)
61+
}

0 commit comments

Comments
 (0)