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

RauliL / varasto / 26652425664

29 May 2026 05:35PM UTC coverage: 94.785% (+2.0%) from 92.759%
26652425664

push

github

RauliL
Run prettier against the codebase

729 of 764 branches covered (95.42%)

Branch coverage included in aggregate %.

2597 of 2745 relevant lines covered (94.61%)

14.44 hits per line

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

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

5
import { tokenize } from './tokenizer';
3✔
6

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

14
export class CommandError extends Error {
3✔
15
  constructor(message: string) {
3✔
16
    super(message);
3✔
17
    this.name = 'CommandError';
3✔
18
  }
3✔
19
}
3✔
20

21
const renderValue = (value: string | object): string =>
3✔
22
  colorize(value, { indent: 2 });
×
23

24
export const renderUsage = (command: CommandDefinition): string =>
3✔
25
  command.args?.map((arg) => `<${arg}>`).join(' ') ?? '';
27✔
26

27
const commands: Readonly<Record<string, CommandDefinition>> = {
3✔
28
  quit: {
3✔
29
    description: 'Exits the command line interface.',
3✔
30
    async callback() {
3✔
31
      process.exit(0);
×
32
    },
×
33
  },
3✔
34
  help: {
3✔
35
    description: 'Displays information about commands.',
3✔
36
    optionalArgs: ['command'],
3✔
37
    async callback(storage, args) {
3✔
38
      if (args.length === 0) {
9✔
39
        for (const name of commandNames) {
3✔
40
          const definition = commands[name];
24✔
41

42
          console.log(`${name} ${renderUsage(definition)}`.trim());
24✔
43
          console.log(definition.description);
24✔
44
          console.log();
24✔
45
        }
24✔
46
        return;
3✔
47
      }
3✔
48

49
      const [command] = args;
6✔
50
      const definition = commands[command];
6✔
51

52
      if (definition) {
9✔
53
        console.log(`${command} ${renderUsage(definition)}`.trim());
3✔
54
        console.log(definition.description);
3✔
55
      } else {
3✔
56
        throw new CommandError(`Unknown command: ${command}`);
3✔
57
      }
3✔
58
    },
9✔
59
  },
3✔
60
  list: {
3✔
61
    description: 'Lists all entries from an namespace.',
3✔
62
    args: ['namespace'],
3✔
63
    async callback(storage, [namespace]) {
3✔
64
      for await (const [key, value] of storage.entries(namespace)) {
×
65
        console.log(renderValue({ [key]: value }));
×
66
      }
×
67
    },
×
68
  },
3✔
69
  keys: {
3✔
70
    description: 'Lists keys of all entries from an namespace.',
3✔
71
    args: ['namespace'],
3✔
72
    async callback(storage, [namespace]) {
3✔
73
      for await (const key of storage.keys(namespace)) {
×
74
        console.log(key);
×
75
      }
×
76
    },
×
77
  },
3✔
78
  get: {
3✔
79
    description: 'Retrieves an entry from an namespace.',
3✔
80
    args: ['namespace', 'key'],
3✔
81
    async callback(storage, [namespace, key]) {
3✔
82
      const value = await storage.get(namespace, key);
×
83

84
      if (value === undefined) {
×
85
        console.error('Entry does not exist.');
×
86
      } else {
×
87
        console.log(renderValue(value));
×
88
      }
×
89
    },
×
90
  },
3✔
91
  set: {
3✔
92
    description: 'Inserts an entry to namespace.',
3✔
93
    args: ['namespace', 'key', 'value'],
3✔
94
    async callback(storage, [namespace, key, value]) {
3✔
95
      await storage.set(namespace, key, JSON5.parse(value));
×
96
    },
×
97
  },
3✔
98
  update: {
3✔
99
    description: 'Patches an already existing entry in namespace.',
3✔
100
    args: ['namespace', 'key', 'value'],
3✔
101
    async callback(storage, [namespace, key, value]) {
3✔
102
      if (key === '*') {
×
103
        for await (const key of storage.keys(namespace)) {
×
104
          console.log(
×
105
            renderValue({
×
106
              [key]: await storage.update(namespace, key, JSON5.parse(value)),
×
107
            })
×
108
          );
×
109
        }
×
110
      } else {
×
111
        console.log(
×
112
          renderValue(await storage.update(namespace, key, JSON5.parse(value)))
×
113
        );
×
114
      }
×
115
    },
×
116
  },
3✔
117
  delete: {
3✔
118
    description: 'Deletes an entry from namespace.',
3✔
119
    args: ['namespace', 'key'],
3✔
120
    async callback(storage, [namespace, key]) {
3✔
121
      if (key === '*') {
×
122
        for await (const key of storage.keys(namespace)) {
×
123
          await storage.delete(namespace, key);
×
124
        }
×
125
      } else {
×
126
        if (!(await storage.delete(namespace, key))) {
×
127
          console.error('Item does not exist.');
×
128
        }
×
129
      }
×
130
    },
×
131
  },
3✔
132
};
3✔
133

134
export const commandNames: Readonly<string[]> = Object.keys(commands).sort();
3✔
135

136
export const runCommand = async (
3✔
137
  storage: Storage,
9✔
138
  input: string
9✔
139
): Promise<void> => {
9✔
140
  const args = tokenize(input);
9✔
141
  let command: CommandDefinition;
9✔
142

143
  if (args.length === 0) {
9!
144
    return;
×
145
  } else if (!(command = commands[args[0]])) {
9!
146
    throw new CommandError(`Unknown command: ${args[0]}`);
×
147
  }
×
148

149
  const minArity = command.args?.length ?? 0;
9!
150
  const maxArity = minArity + (command.optionalArgs?.length ?? 0);
9!
151
  const providedArity = args.length - 1;
9✔
152

153
  if (providedArity < minArity) {
9!
154
    throw new CommandError(`Missing arguments for command ${args[0]}`);
×
155
  } else if (providedArity > maxArity) {
9!
156
    throw new CommandError(`Too many arguments for command ${args[0]}`);
×
157
  }
×
158

159
  await command.callback(storage, args.slice(1));
9✔
160
};
6✔
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