char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somport console extension to typescript1738b3c

main
4.9 KiB172 linesraw
1import {
2  ArrayPrototypeUnshift,
3  Error,
4  ErrorCaptureStackTrace,
5  ErrorGetStack,
6  Map,
7  MapPrototypeDelete,
8  MapPrototypeGet,
9  MapPrototypeHas,
10  MapPrototypeSet,
11  MathMin,
12  NumberPrototypeToFixed,
13  ObjectCreate,
14  ObjectDefineProperty,
15  ObjectGetOwnPropertyDescriptor,
16  ObjectPrototype,
17  ObjectSetPrototypeOf,
18  StringPrototypeRepeat,
19  StringPrototypeReplaceAll,
20  SymbolToStringTag,
21  TypeError,
22} from "ext:core/primordials";
23import {
24  op_console_clear,
25  op_console_colors,
26  op_console_now,
27  op_console_print,
28} from "ext:core/ops";
29import { onRuntimeStart } from "ext:core/bootstrap";
30import { inspect } from "./inspect.js";
31import { format, labelString } from "./format.js";
32import { table } from "./table.js";
33
34const counters = new Map<string, number>();
35const timers = new Map<string, number>();
36let groupDepth = 0;
37let stdoutColors: boolean | undefined, stderrColors: boolean | undefined;
38onRuntimeStart(() => {
39  stdoutColors = op_console_colors(false);
40  stderrColors = op_console_colors(true);
41});
42
43function print(stderr: boolean, text: unknown): void {
44  const indent = StringPrototypeRepeat("  ", MathMin(groupDepth, 20));
45  op_console_print([
46    stderr,
47    `${indent}${StringPrototypeReplaceAll(text, "\n", `\n${indent}`)}\n`,
48  ]);
49}
50
51function logger(stderr: boolean, args: unknown[]): void {
52  if (args.length) {
53    print(stderr, format(args, stderr ? stderrColors : stdoutColors));
54  }
55}
56
57function elapsed(label: string): string | null {
58  if (!MapPrototypeHas(timers, label)) {
59    print(true, `Timer '${label}' does not exist`);
60    return null;
61  }
62  const duration = op_console_now() - MapPrototypeGet(timers, label)!;
63  return `${label}: ${NumberPrototypeToFixed(duration, 3)} ms`;
64}
65
66const console = {
67  log(...args: unknown[]) {
68    logger(false, args);
69  },
70  debug(...args: unknown[]) {
71    logger(false, args);
72  },
73  info(...args: unknown[]) {
74    logger(false, args);
75  },
76  warn(...args: unknown[]) {
77    logger(true, args);
78  },
79  error(...args: unknown[]) {
80    logger(true, args);
81  },
82  assert(condition: unknown = false, ...args: unknown[]) {
83    if (condition) return;
84    if (typeof args[0] === "string") args[0] = `Assertion failed: ${args[0]}`;
85    else ArrayPrototypeUnshift(args, "Assertion failed");
86    logger(true, args);
87  },
88  clear() {
89    groupDepth = 0;
90    op_console_clear();
91  },
92  count(value: unknown = "default") {
93    const label = labelString(value);
94    const count = (MapPrototypeGet(counters, label) || 0) + 1;
95    MapPrototypeSet(counters, label, count);
96    print(false, `${label}: ${count}`);
97  },
98  countReset(value: unknown = "default") {
99    const label = labelString(value);
100    if (MapPrototypeHas(counters, label)) MapPrototypeSet(counters, label, 0);
101    else print(true, `Count for '${label}' does not exist`);
102  },
103  dir(value: unknown = undefined, options: unknown = undefined) {
104    if (
105      options !== undefined && options !== null &&
106      typeof options !== "object" && typeof options !== "function"
107    ) {
108      throw new TypeError("Console dir options must be an object");
109    }
110    const depth: unknown = options
111      ? ObjectGetOwnPropertyDescriptor(options, "depth")?.value
112      : undefined;
113    print(false, inspect(value, { depth, colors: stdoutColors }));
114  },
115  dirxml(...args: unknown[]) {
116    logger(false, args);
117  },
118  group(...args: unknown[]) {
119    print(false, args.length ? format(args, stdoutColors) : "group");
120    groupDepth++;
121  },
122  groupCollapsed(...args: unknown[]) {
123    print(false, args.length ? format(args, stdoutColors) : "group");
124    groupDepth++;
125  },
126  groupEnd() {
127    if (groupDepth) groupDepth--;
128  },
129  table(data: unknown = undefined, columns: unknown = undefined) {
130    table(data, columns, print);
131  },
132  time(value: unknown = "default") {
133    const label = labelString(value);
134    if (MapPrototypeHas(timers, label)) {
135      print(true, `Timer '${label}' already exists`);
136    } else MapPrototypeSet(timers, label, op_console_now());
137  },
138  timeLog(label: unknown = "default", ...args: unknown[]) {
139    const text = elapsed(labelString(label));
140    if (text !== null) {
141      print(
142        false,
143        args.length ? `${text} ${format(args, stdoutColors)}` : text,
144      );
145    }
146  },
147  timeEnd(value: unknown = "default") {
148    const label = labelString(value);
149    const text = elapsed(label);
150    if (text !== null) {
151      MapPrototypeDelete(timers, label);
152      print(false, text);
153    }
154  },
155  trace(...args: unknown[]) {
156    const error = new Error(args.length ? format(args) : "");
157    ObjectDefineProperty(error, "name", { value: "Trace", configurable: true });
158    ErrorCaptureStackTrace(error, traceMethod);
159    print(true, ErrorGetStack(error));
160  },
161};
162const traceMethod = console.trace;
163ObjectSetPrototypeOf(console, ObjectCreate(ObjectPrototype));
164ObjectDefineProperty(console, SymbolToStringTag, {
165  value: "console",
166  configurable: true,
167});
168ObjectDefineProperty(globalThis, "console", {
169  value: console,
170  writable: true,
171  configurable: true,
172});