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

RauliL / juokse / 6077080524

04 Sep 2023 07:36PM UTC coverage: 72.289% (-2.0%) from 74.324%
6077080524

push

github

web-flow
Merge pull request #23 from RauliL/interactive

Add very simple interactive mode

172 of 242 branches covered (0.0%)

Branch coverage included in aggregate %.

26 of 26 new or added lines in 4 files covered. (100.0%)

488 of 671 relevant lines covered (72.73%)

140.77 hits per line

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

0.0
/src/cli.ts
1
import chalk, { ChalkFunction } from "chalk";
×
2
import { program } from "commander";
×
3
import { format } from "date-fns";
×
4
import fs from "fs";
×
5
import { sync as readPackageSync } from "read-pkg";
×
6
import stripAnsi from "strip-ansi";
×
7

8
import { compile } from "./compiler";
×
9
import { Context } from "./context";
×
10
import { executeScript } from "./execute";
×
11
import { runInteractive } from "./interactive";
×
12
import { ExitStatus } from "./status";
×
13

14
type CommandLineOptions = {
15
  args: string[];
16
  echo: boolean;
17
  filename?: string;
18
  stripAnsi: boolean;
19
  timeStampFormat: "HH:mm:ss";
20
};
21

22
const parseCommandLineOptions = (): CommandLineOptions => {
×
23
  program
×
24
    .version(readPackageSync().version)
25
    .usage("[options] [file] [arguments]")
26
    .option("-s, --strip-ansi", "Strip ANSI escape codes from process outputs")
27
    .option("-t, --time-stamp-format [format]", "Specify format of timestamps")
28
    .option("--no-echo", "Do not output executed commands")
29
    .parse(process.argv);
30

31
  const opts = program.opts();
×
32
  let filename: string | undefined;
33
  let args: string[];
34

35
  if (program.args.length > 0) {
×
36
    args = program.args.slice(1);
×
37
    if (program.args[0] !== "-") {
×
38
      filename = program.args[0];
×
39
    }
40
  } else {
41
    args = [];
×
42
  }
43

44
  return {
×
45
    args,
46
    echo: opts.echo,
47
    filename,
48
    stripAnsi: opts.stripAnsi,
49
    timeStampFormat: opts.timeStampFormat ?? "HH:mm:ss",
×
50
  };
51
};
52

53
const log = (
×
54
  options: CommandLineOptions,
55
  input: Buffer | Error | string,
56
  stream: NodeJS.WriteStream,
57
  color: ChalkFunction | null = null
×
58
) => {
59
  // Convert buffer into string and remove any trailing new lines.
60
  const text = input.toString().replace(/(\r?\n){1,2}$/, "");
×
61

62
  if (!text.length) {
×
63
    return;
×
64
  }
65

66
  text.split(/\r?\n/).forEach((line) => {
×
67
    let timeStamp = "";
×
68

69
    if (options.timeStampFormat) {
×
70
      timeStamp = `[${chalk.grey(
×
71
        format(Date.now(), options.timeStampFormat)
72
      )}] `;
73
    }
74
    if (options.stripAnsi) {
×
75
      line = stripAnsi(line);
×
76
    }
77
    if (color) {
×
78
      line = color(line);
×
79
    }
80
    stream.write(`${timeStamp}${line.replace(/\r?\n$/, "")}\n`);
×
81
  });
82
};
83

84
const createContext = (options: CommandLineOptions): Context => {
×
85
  const instance = new Context();
×
86

87
  // Copy environment variables from system into context.
88
  Object.assign(instance.environment, process.env);
×
89

90
  instance.variables["0"] = options.filename ?? "";
×
91
  instance.variables["#"] = `${options.args.length}`;
×
92
  instance.variables["*"] = options.args.join(" ");
×
93
  for (let i = 0; i < options.args.length; ++i) {
×
94
    instance.variables[i + 1] = options.args[i];
×
95
  }
96

97
  instance.on("exit", (status) => process.exit(status));
×
98

99
  if (options.echo) {
×
100
    instance.on("process start", ({ executable, args }) => {
×
101
      log(
×
102
        options,
103
        `${[executable, ...args].join(" ")}`,
104
        process.stdout,
105
        chalk.green
106
      );
107
    });
108
  }
109

110
  instance.stdout.on("data", (data) => log(options, data, process.stdout));
×
111
  instance.stderr.on("data", (data) =>
×
112
    log(options, data, process.stderr, chalk.red)
×
113
  );
114

115
  return instance;
×
116
};
117

118
const execute = (
×
119
  options: CommandLineOptions,
120
  context: Context,
121
  source: string,
122
  filename: string
123
) => {
124
  compile(filename, source)
×
125
    .then((script) => executeScript(context, script))
×
126
    .catch((err) => {
127
      log(options, err, process.stderr, chalk.red);
×
128
      process.exit(ExitStatus.ERROR);
×
129
    });
130
};
131

132
export const run = () => {
×
133
  const options = parseCommandLineOptions();
×
134
  const context = createContext(options);
×
135

136
  if (options.filename) {
×
137
    execute(
×
138
      options,
139
      context,
140
      fs.readFileSync(options.filename, "utf-8"),
141
      options.filename
142
    );
143
  } else if (process.stdin.isTTY) {
×
144
    runInteractive(context);
×
145
  } else {
146
    let source = "";
×
147

148
    process.stdin.resume();
×
149
    process.stdin.on("data", (buffer) => {
×
150
      source += buffer.toString();
×
151
    });
152
    process.stdin.on("end", () => {
×
153
      execute(options, context, source, "<stdin>");
×
154
    });
155
  }
156
};
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