• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

RauliL / varasto / 20748408327

06 Jan 2026 12:33PM UTC coverage: 91.361% (-3.8%) from 95.173%
20748408327

push

github

web-flow
Merge pull request #149 from RauliL/cli

Add CLI

674 of 718 branches covered (93.87%)

Branch coverage included in aggregate %.

39 of 171 new or added lines in 4 files covered. (22.81%)

2319 of 2558 relevant lines covered (90.66%)

13.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.96
/packages/cli/src/command.ts
1
import { Storage } from '@varasto/storage';
3✔
NEW
2
import JSON5 from 'json5';
×
NEW
3
import { colorize } from 'json-colorizer';
×
4

NEW
5
import { tokenize } from './tokenizer';
×
6

7
export type CommandDefinition = {
8
  description: string;
9
  args?: string[];
10
  callback: (storage: Storage, args: string[]) => Promise<void>;
11
};
12

NEW
13
const renderValue = (value: any): string => colorize(value, { indent: 2 });
×
14

NEW
15
export const renderUsage = (command: CommandDefinition): string =>
×
NEW
16
  command.args?.map((arg) => `<${arg}>`).join(' ') ?? '';
×
17

NEW
18
const commands: Readonly<Record<string, CommandDefinition>> = {
×
NEW
19
  quit: {
×
NEW
20
    description: 'Exits the command line interface.',
×
NEW
21
    async callback() {
×
NEW
22
      process.exit(0);
×
NEW
23
    },
×
NEW
24
  },
×
NEW
25
  help: {
×
NEW
26
    description: 'Displays information about an command.',
×
NEW
27
    args: ['command'],
×
NEW
28
    async callback(storage, [command]) {
×
NEW
29
      const definition = commands[command];
×
30

NEW
31
      if (definition) {
×
NEW
32
        console.log(`${command} ${renderUsage(definition)}`);
×
NEW
33
        console.log(definition.description);
×
NEW
34
      } else {
×
NEW
35
        throw new Error(`Unknown command: ${command}`);
×
NEW
36
      }
×
NEW
37
    },
×
NEW
38
  },
×
NEW
39
  list: {
×
NEW
40
    description: 'Lists all entries from an namespace.',
×
NEW
41
    args: ['namespace'],
×
NEW
42
    async callback(storage, [namespace]) {
×
NEW
43
      for await (const [key, value] of storage.entries(namespace)) {
×
NEW
44
        console.log(renderValue({ key: value }));
×
NEW
45
      }
×
NEW
46
    },
×
NEW
47
  },
×
NEW
48
  keys: {
×
NEW
49
    description: 'Lists keys of all entries from an namespace.',
×
NEW
50
    args: ['namespace'],
×
NEW
51
    async callback(storage, [namespace]) {
×
NEW
52
      for await (const key of storage.keys(namespace)) {
×
NEW
53
        console.log(key);
×
NEW
54
      }
×
NEW
55
    },
×
NEW
56
  },
×
NEW
57
  get: {
×
NEW
58
    description: 'Retrieves an entry from an namespace.',
×
NEW
59
    args: ['namespace', 'key'],
×
NEW
60
    async callback(storage, [namespace, key]) {
×
NEW
61
      const value = await storage.get(namespace, key);
×
62

NEW
63
      if (value === undefined) {
×
NEW
64
        console.error('Entry does not exist.');
×
NEW
65
      } else {
×
NEW
66
        console.log(renderValue(value));
×
NEW
67
      }
×
NEW
68
    },
×
NEW
69
  },
×
NEW
70
  set: {
×
NEW
71
    description: 'Inserts an entry to namespace.',
×
NEW
72
    args: ['namespace', 'key', 'value'],
×
NEW
73
    async callback(storage, [namespace, key, value]) {
×
NEW
74
      await storage.set(namespace, key, JSON5.parse(value));
×
NEW
75
    },
×
NEW
76
  },
×
NEW
77
  update: {
×
NEW
78
    description: 'Patches an already existing entry in namespace.',
×
NEW
79
    args: ['namespace', 'key', 'value'],
×
NEW
80
    async callback(storage, [namespace, key, value]) {
×
NEW
81
      console.log(
×
NEW
82
        renderValue(await storage.update(namespace, key, JSON5.parse(value)))
×
NEW
83
      );
×
NEW
84
    },
×
NEW
85
  },
×
NEW
86
  delete: {
×
NEW
87
    description: 'Deletes an entry from namespace.',
×
NEW
88
    args: ['namespace', 'key'],
×
NEW
89
    async callback(storage, [namespace, key]) {
×
NEW
90
      if (!(await storage.delete(namespace, key))) {
×
NEW
91
        console.error('Item does not exist.');
×
NEW
92
      }
×
NEW
93
    },
×
NEW
94
  },
×
NEW
95
};
×
96

NEW
97
export const commandNames: Readonly<string[]> = Object.keys(commands).sort();
×
98

NEW
99
export const runCommand = async (
×
NEW
100
  storage: Storage,
×
NEW
101
  input: string
×
NEW
102
): Promise<void> => {
×
NEW
103
  const args = tokenize(input);
×
NEW
104
  let command: CommandDefinition;
×
NEW
105
  let arity: number;
×
106

NEW
107
  if (args.length === 0) {
×
NEW
108
    return;
×
NEW
109
  } else if (!(command = commands[args[0]])) {
×
NEW
110
    throw new Error(`Unknown command: ${args[0]}`);
×
NEW
111
  }
×
112

NEW
113
  arity = command.args?.length ?? 0;
×
NEW
114
  if (args.length - 1 < arity) {
×
NEW
115
    throw new Error(`Missing arguments for command ${args[0]}`);
×
NEW
116
  } else if (args.length - 1 > arity) {
×
NEW
117
    throw new Error(`Too many arguments for command ${args[0]}`);
×
NEW
118
  }
×
119

NEW
120
  await command.callback(storage, args.slice(1));
×
NEW
121
};
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc