@johannes.latzel/terminal 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +35 -0
  3. package/dist/command-arguments.d.ts +120 -0
  4. package/dist/command-arguments.d.ts.map +1 -0
  5. package/dist/command-arguments.js +155 -0
  6. package/dist/command-arguments.js.map +1 -0
  7. package/dist/command-factory.d.ts +17 -0
  8. package/dist/command-factory.d.ts.map +1 -0
  9. package/dist/command-factory.js +43 -0
  10. package/dist/command-factory.js.map +1 -0
  11. package/dist/command-tree.d.ts +40 -0
  12. package/dist/command-tree.d.ts.map +1 -0
  13. package/dist/command-tree.js +77 -0
  14. package/dist/command-tree.js.map +1 -0
  15. package/dist/commands/clear.d.ts +10 -0
  16. package/dist/commands/clear.d.ts.map +1 -0
  17. package/dist/commands/clear.js +13 -0
  18. package/dist/commands/clear.js.map +1 -0
  19. package/dist/commands/exit.d.ts +10 -0
  20. package/dist/commands/exit.d.ts.map +1 -0
  21. package/dist/commands/exit.js +13 -0
  22. package/dist/commands/exit.js.map +1 -0
  23. package/dist/commands/help.d.ts +40 -0
  24. package/dist/commands/help.d.ts.map +1 -0
  25. package/dist/commands/help.js +136 -0
  26. package/dist/commands/help.js.map +1 -0
  27. package/dist/completion/completer.d.ts +22 -0
  28. package/dist/completion/completer.d.ts.map +1 -0
  29. package/dist/completion/completer.js +55 -0
  30. package/dist/completion/completer.js.map +1 -0
  31. package/dist/errors.d.ts +18 -0
  32. package/dist/errors.d.ts.map +1 -0
  33. package/dist/errors.js +28 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/hook.d.ts +11 -0
  36. package/dist/hook.d.ts.map +1 -0
  37. package/dist/hook.js +16 -0
  38. package/dist/hook.js.map +1 -0
  39. package/dist/hooks.d.ts +21 -0
  40. package/dist/hooks.d.ts.map +1 -0
  41. package/dist/hooks.js +17 -0
  42. package/dist/hooks.js.map +1 -0
  43. package/dist/index.d.ts +10 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +8 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/input/args-parser.d.ts +22 -0
  48. package/dist/input/args-parser.d.ts.map +1 -0
  49. package/dist/input/args-parser.js +52 -0
  50. package/dist/input/args-parser.js.map +1 -0
  51. package/dist/input/parser.d.ts +14 -0
  52. package/dist/input/parser.d.ts.map +1 -0
  53. package/dist/input/parser.js +65 -0
  54. package/dist/input/parser.js.map +1 -0
  55. package/dist/terminal-hook-builder.d.ts +42 -0
  56. package/dist/terminal-hook-builder.d.ts.map +1 -0
  57. package/dist/terminal-hook-builder.js +48 -0
  58. package/dist/terminal-hook-builder.js.map +1 -0
  59. package/dist/terminal.d.ts +86 -0
  60. package/dist/terminal.d.ts.map +1 -0
  61. package/dist/terminal.js +274 -0
  62. package/dist/terminal.js.map +1 -0
  63. package/dist/types.d.ts +80 -0
  64. package/dist/types.d.ts.map +1 -0
  65. package/dist/types.js +85 -0
  66. package/dist/types.js.map +1 -0
  67. package/package.json +82 -0
@@ -0,0 +1,136 @@
1
+ import { Command, CommandContainer } from '../types.js';
2
+ import { z } from 'zod';
3
+ /** Left-pad a string with spaces to a minimum width. */
4
+ function leftPad(str, len) {
5
+ return str + ' '.repeat(Math.max(0, len - str.length));
6
+ }
7
+ /**
8
+ * Render a global help listing for a set of root commands.
9
+ * Each command is shown as `name description`, names are
10
+ * left-aligned to the longest command name.
11
+ */
12
+ export function globalHelp(commands) {
13
+ const maxNameLen = Math.max(...commands.map((c) => c.name().length), 0);
14
+ const lines = ['Commands:'];
15
+ for (const cmd of commands) {
16
+ const desc = cmd.description() ?? '';
17
+ lines.push(` ${leftPad(cmd.name(), maxNameLen)} ${desc}`);
18
+ }
19
+ return lines.join('\n');
20
+ }
21
+ function renderCommandArgumentDefinitions(argDefs) {
22
+ if (argDefs.length === 0)
23
+ return [];
24
+ const lines = ['', 'Arguments:'];
25
+ const maxNameLen = Math.max(...argDefs.map((a) => a.name.length));
26
+ for (const arg of argDefs) {
27
+ const label = `--${arg.name}`;
28
+ const required = arg.required ? ' (required)' : '';
29
+ const desc = arg.description ?? '';
30
+ lines.push(` ${leftPad(label, maxNameLen + 2)} ${desc}${required}`);
31
+ }
32
+ return lines;
33
+ }
34
+ /**
35
+ * Render detailed help for a single command, including its
36
+ * name, description, argument definitions, and subcommands.
37
+ */
38
+ export function commandHelp(command) {
39
+ const lines = [];
40
+ const globalDesc = command.description();
41
+ if (globalDesc) {
42
+ lines.push(`${command.name()} - ${globalDesc}`);
43
+ }
44
+ else {
45
+ lines.push(command.name());
46
+ }
47
+ lines.push(...renderCommandArgumentDefinitions(command.definitions()));
48
+ if (command instanceof CommandContainer) {
49
+ const subs = command.commands();
50
+ if (subs.length > 0) {
51
+ const maxNameLen = Math.max(...subs.map((c) => c.name().length));
52
+ lines.push('');
53
+ lines.push('Subcommands:');
54
+ for (const sub of subs) {
55
+ const desc = sub.description() ?? '';
56
+ lines.push(` ${leftPad(sub.name(), maxNameLen)} ${desc}`);
57
+ }
58
+ }
59
+ }
60
+ return lines.join('\n');
61
+ }
62
+ /**
63
+ * Resolve a token path against a command list and render
64
+ * help for the resolved command. Returns an error message
65
+ * if the path does not match any command.
66
+ */
67
+ export function scopedHelp(commands, pathTokens) {
68
+ const resolved = resolveCommand(commands, pathTokens);
69
+ if (!resolved) {
70
+ return `Unknown command: ${pathTokens.join(' ')}`;
71
+ }
72
+ return commandHelp(resolved);
73
+ }
74
+ /**
75
+ * Walk the command tree matching each token to a command name.
76
+ * Returns the deepest matching command, or `undefined` if a token
77
+ * cannot be matched or extra tokens trail a leaf node.
78
+ */
79
+ export function resolveCommand(commands, tokens) {
80
+ let level = commands;
81
+ let matched;
82
+ for (const token of tokens) {
83
+ matched = level.find((c) => c.name() === token);
84
+ if (!matched)
85
+ return undefined;
86
+ if (matched instanceof CommandContainer) {
87
+ const subs = matched.commands();
88
+ if (subs.length > 0) {
89
+ level = subs;
90
+ continue;
91
+ }
92
+ }
93
+ if (token !== tokens[tokens.length - 1]) {
94
+ return undefined;
95
+ }
96
+ }
97
+ return matched;
98
+ }
99
+ /**
100
+ * Built-in `help` command. Lists all commands or shows detailed
101
+ * help for a specific command by name.
102
+ *
103
+ * @example
104
+ * ```
105
+ * > help # list all commands
106
+ * > help --command config # show help for the "config" command
107
+ * ```
108
+ */
109
+ export class HelpCommand extends Command {
110
+ constructor() {
111
+ super('help', 'Show help', [
112
+ {
113
+ name: 'command',
114
+ description: 'Show help for a specific command',
115
+ required: false,
116
+ schema: z.string()
117
+ }
118
+ ]);
119
+ }
120
+ async execute(ctx, args) {
121
+ const roots = ctx.terminal.getRootCommands();
122
+ if (args.has('command')) {
123
+ const cmdName = await args.require('command');
124
+ const cmd = roots.find((c) => c.name() === cmdName);
125
+ if (!cmd) {
126
+ ctx.stdout.write(`Unknown command: ${cmdName}\n`);
127
+ return;
128
+ }
129
+ ctx.stdout.write(commandHelp(cmd) + '\n');
130
+ }
131
+ else {
132
+ ctx.stdout.write(globalHelp(roots) + '\n');
133
+ }
134
+ }
135
+ }
136
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/commands/help.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { CommandTree } from '../command-tree.js';
2
+ export interface Completion {
3
+ /** Matching command names. */
4
+ matches: string[];
5
+ /** The partial token that was matched against. */
6
+ partial: string;
7
+ }
8
+ /**
9
+ * Tab-completion engine powered by the command tree.
10
+ * Walks the tree to find commands matching the current input
11
+ * prefix, supporting multi-level completion through containers
12
+ * and --flag completion for commands with argument definitions.
13
+ */
14
+ export declare class Completer {
15
+ private tree;
16
+ constructor(tree: CommandTree);
17
+ /**
18
+ * Compute completions for a partial input line.
19
+ */
20
+ complete(line: string): Completion;
21
+ }
22
+ //# sourceMappingURL=completer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completer.d.ts","sourceRoot":"","sources":["../../src/completion/completer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,MAAM,WAAW,UAAU;IACvB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,qBAAa,SAAS;IACN,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,WAAW;IAErC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU;CAwCrC"}
@@ -0,0 +1,55 @@
1
+ import { CommandContainer } from '../types.js';
2
+ import { tokenize } from '../input/parser.js';
3
+ /**
4
+ * Tab-completion engine powered by the command tree.
5
+ * Walks the tree to find commands matching the current input
6
+ * prefix, supporting multi-level completion through containers
7
+ * and --flag completion for commands with argument definitions.
8
+ */
9
+ export class Completer {
10
+ tree;
11
+ constructor(tree) {
12
+ this.tree = tree;
13
+ }
14
+ /**
15
+ * Compute completions for a partial input line.
16
+ */
17
+ complete(line) {
18
+ const tokens = tokenize(line);
19
+ const trailingSpace = line.endsWith(' ');
20
+ if (tokens.length === 0 && !trailingSpace) {
21
+ return { matches: this.tree.getRoots().map((c) => c.name()), partial: '' };
22
+ }
23
+ const partial = trailingSpace ? '' : tokens[tokens.length - 1];
24
+ const prefix = trailingSpace ? tokens : tokens.slice(0, -1);
25
+ let lastMatched = null;
26
+ let commands = this.tree.getRoots();
27
+ for (const token of prefix) {
28
+ if (token.startsWith('--'))
29
+ continue;
30
+ const cmd = commands.find((command) => command.name() === token);
31
+ if (!cmd)
32
+ return { matches: [], partial: line };
33
+ lastMatched = cmd;
34
+ if (!(cmd instanceof CommandContainer))
35
+ break;
36
+ commands = cmd.commands();
37
+ }
38
+ if (lastMatched && !(lastMatched instanceof CommandContainer)) {
39
+ const flagPartial = partial.startsWith('--') ? partial : partial === '' ? '--' : null;
40
+ if (flagPartial !== null) {
41
+ const matches = lastMatched
42
+ .definitions()
43
+ .filter((a) => `--${a.name}`.startsWith(flagPartial))
44
+ .map((a) => `--${a.name}`);
45
+ return { matches, partial };
46
+ }
47
+ return { matches: [], partial };
48
+ }
49
+ const matches = commands
50
+ .filter((command) => command.name().startsWith(partial))
51
+ .map((c) => c.name());
52
+ return { matches, partial };
53
+ }
54
+ }
55
+ //# sourceMappingURL=completer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completer.js","sourceRoot":"","sources":["../../src/completion/completer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /** Thrown when no command matches the input tokens. */
2
+ export declare class CommandNotFoundError extends Error {
3
+ readonly suggestions: string[];
4
+ /**
5
+ * @param message - Human-readable error description.
6
+ * @param suggestions - Prefix-matched command names to suggest.
7
+ */
8
+ constructor(message: string, suggestions?: string[]);
9
+ }
10
+ /** Thrown when a command receives invalid arguments. */
11
+ export declare class InvalidArgumentsError extends Error {
12
+ constructor(message: string);
13
+ }
14
+ /** Thrown when input cannot be tokenized (e.g. unclosed quotes). */
15
+ export declare class ParseError extends Error {
16
+ constructor(message: string);
17
+ }
18
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,qBAAa,oBAAqB,SAAQ,KAAK;aAOvB,WAAW,EAAE,MAAM,EAAE;IANzC;;;OAGG;gBAEC,OAAO,EAAE,MAAM,EACC,WAAW,GAAE,MAAM,EAAO;CAKjD;AAED,wDAAwD;AACxD,qBAAa,qBAAsB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI9B;AAED,oEAAoE;AACpE,qBAAa,UAAW,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM;CAI9B"}
package/dist/errors.js ADDED
@@ -0,0 +1,28 @@
1
+ /** Thrown when no command matches the input tokens. */
2
+ export class CommandNotFoundError extends Error {
3
+ suggestions;
4
+ /**
5
+ * @param message - Human-readable error description.
6
+ * @param suggestions - Prefix-matched command names to suggest.
7
+ */
8
+ constructor(message, suggestions = []) {
9
+ super(message);
10
+ this.suggestions = suggestions;
11
+ this.name = 'CommandNotFoundError';
12
+ }
13
+ }
14
+ /** Thrown when a command receives invalid arguments. */
15
+ export class InvalidArgumentsError extends Error {
16
+ constructor(message) {
17
+ super(message);
18
+ this.name = 'InvalidArgumentsError';
19
+ }
20
+ }
21
+ /** Thrown when input cannot be tokenized (e.g. unclosed quotes). */
22
+ export class ParseError extends Error {
23
+ constructor(message) {
24
+ super(message);
25
+ this.name = 'ParseError';
26
+ }
27
+ }
28
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAOvB;IANpB;;;OAGG;IACH,YACI,OAAe,EACC,cAAwB,EAAE;QAE1C,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,gBAAW,GAAX,WAAW,CAAe;QAG1C,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACvC,CAAC;CACJ;AAED,wDAAwD;AACxD,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC5C,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACxC,CAAC;CACJ;AAED,oEAAoE;AACpE,MAAM,OAAO,UAAW,SAAQ,KAAK;IACjC,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC7B,CAAC;CACJ"}
package/dist/hook.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /** Base class for all hooks. Call {@link dispose} to unsubscribe. */
2
+ export declare abstract class Hook {
3
+ private _disposed;
4
+ /** Unsubscribe this hook. Safe to call multiple times. */
5
+ dispose(): void;
6
+ /** Whether this hook has been disposed. */
7
+ protected isDisposed(): boolean;
8
+ /** Override to clean up subscriptions. Called once by {@link dispose}. */
9
+ protected abstract onDispose(): void;
10
+ }
11
+ //# sourceMappingURL=hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,8BAAsB,IAAI;IACtB,OAAO,CAAC,SAAS,CAAS;IAE1B,0DAA0D;IAC1D,OAAO,IAAI,IAAI;IAMf,2CAA2C;IAC3C,SAAS,CAAC,UAAU,IAAI,OAAO;IAI/B,0EAA0E;IAC1E,SAAS,CAAC,QAAQ,CAAC,SAAS,IAAI,IAAI;CACvC"}
package/dist/hook.js ADDED
@@ -0,0 +1,16 @@
1
+ /** Base class for all hooks. Call {@link dispose} to unsubscribe. */
2
+ export class Hook {
3
+ _disposed = false;
4
+ /** Unsubscribe this hook. Safe to call multiple times. */
5
+ dispose() {
6
+ if (this._disposed)
7
+ return;
8
+ this._disposed = true;
9
+ this.onDispose();
10
+ }
11
+ /** Whether this hook has been disposed. */
12
+ isDisposed() {
13
+ return this._disposed;
14
+ }
15
+ }
16
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,MAAM,OAAgB,IAAI;IACd,SAAS,GAAG,KAAK,CAAC;IAE1B,0DAA0D;IAC1D,OAAO;QACH,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC;IAED,2CAA2C;IACjC,UAAU;QAChB,OAAO,IAAI,CAAC,SAAS,CAAC;IAC1B,CAAC;CAIJ"}
@@ -0,0 +1,21 @@
1
+ import { Hook } from './hook.js';
2
+ import type { Command, CommandContext } from './types.js';
3
+ import type { CommandArguments } from './command-arguments.js';
4
+ export declare class TypedHook<TArgs extends any[], TReturn> extends Hook {
5
+ private readonly fn;
6
+ private readonly onDisposeCb;
7
+ constructor(fn: (...args: TArgs) => TReturn, onDisposeCb: () => void);
8
+ exec(...args: TArgs): TReturn;
9
+ protected onDispose(): void;
10
+ }
11
+ export type BeforeParseHook = TypedHook<[string], string | Promise<string>>;
12
+ export type AfterParseHook = TypedHook<[string[]], string[] | Promise<string[]>>;
13
+ export type BeforeExecuteHook = TypedHook<[
14
+ Command,
15
+ CommandContext,
16
+ CommandArguments
17
+ ], void | false | Promise<void | false>>;
18
+ export type AfterExecuteHook = TypedHook<[unknown], void | Promise<void>>;
19
+ export type BeforeExitHook = TypedHook<[], void | Promise<void>>;
20
+ export type OnErrorHook = TypedHook<[Error], void | boolean | Promise<void | boolean>>;
21
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,qBAAa,SAAS,CAAC,KAAK,SAAS,GAAG,EAAE,EAAE,OAAO,CAAE,SAAQ,IAAI;IAEzD,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,WAAW;gBADX,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,EAC/B,WAAW,EAAE,MAAM,IAAI;IAK5C,IAAI,CAAC,GAAG,IAAI,EAAE,KAAK,GAAG,OAAO;IAI7B,SAAS,CAAC,SAAS,IAAI,IAAI;CAG9B;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5E,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AACjF,MAAM,MAAM,iBAAiB,GAAG,SAAS,CACrC;IAAC,OAAO;IAAE,cAAc;IAAE,gBAAgB;CAAC,EAC3C,IAAI,GAAG,KAAK,GAAG,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,CACvC,CAAC;AACF,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1E,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACjE,MAAM,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC"}
package/dist/hooks.js ADDED
@@ -0,0 +1,17 @@
1
+ import { Hook } from './hook.js';
2
+ export class TypedHook extends Hook {
3
+ fn;
4
+ onDisposeCb;
5
+ constructor(fn, onDisposeCb) {
6
+ super();
7
+ this.fn = fn;
8
+ this.onDisposeCb = onDisposeCb;
9
+ }
10
+ exec(...args) {
11
+ return this.fn(...args);
12
+ }
13
+ onDispose() {
14
+ this.onDisposeCb();
15
+ }
16
+ }
17
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,MAAM,OAAO,SAAwC,SAAQ,IAAI;IAExC;IACA;IAFrB,YACqB,EAA+B,EAC/B,WAAuB;QAExC,KAAK,EAAE,CAAC;QAHS,OAAE,GAAF,EAAE,CAA6B;QAC/B,gBAAW,GAAX,WAAW,CAAY;IAG5C,CAAC;IAED,IAAI,CAAC,GAAG,IAAW;QACf,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IAC5B,CAAC;IAES,SAAS;QACf,IAAI,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;CACJ"}
@@ -0,0 +1,10 @@
1
+ export { Terminal } from './terminal.js';
2
+ export { CommandArguments } from './command-arguments.js';
3
+ export { InvalidArgumentsError, CommandNotFoundError, ParseError } from './errors.js';
4
+ export { Hook } from './hook.js';
5
+ export { TerminalHookBuilder } from './terminal-hook-builder.js';
6
+ export { Command, CommandContainer } from './types.js';
7
+ export { command, container, arg } from './command-factory.js';
8
+ export type { CommandArgumentDefinition } from './command-arguments.js';
9
+ export type { CommandContext, Logger, TerminalOptions } from './types.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAC/D,YAAY,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACxE,YAAY,EAAE,cAAc,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { Terminal } from './terminal.js';
2
+ export { CommandArguments } from './command-arguments.js';
3
+ export { InvalidArgumentsError, CommandNotFoundError, ParseError } from './errors.js';
4
+ export { Hook } from './hook.js';
5
+ export { TerminalHookBuilder } from './terminal-hook-builder.js';
6
+ export { Command, CommandContainer } from './types.js';
7
+ export { command, container, arg } from './command-factory.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { CommandArgumentDefinition } from '../command-arguments.js';
2
+ /**
3
+ * Parse an array of tokens into a record of `--name value` pairs.
4
+ *
5
+ * - `--name value` produces `{ name: "value" }`
6
+ * - `--flag` (no next token or next token starts with `--`) produces
7
+ * `{ flag: "true" }` (boolean-shorthand)
8
+ * - When `argDefs` is provided, tokens not starting with `--` are
9
+ * matched against argument definitions with a `position` index
10
+ * and consumed in position order.
11
+ *
12
+ * @param tokens - Tokens remaining after command matching.
13
+ * @param argDefs - Optional argument definitions; those with a
14
+ * `position` field are treated as positional (bare token) args.
15
+ * @returns A record mapping argument names (without `--` prefix) to
16
+ * their string values.
17
+ * @throws {InvalidArgumentsError} When a token does not start with
18
+ * `--` (and no positional definition matches), or an empty `--`
19
+ * is encountered.
20
+ */
21
+ export declare function parseFlags(tokens: string[], argDefs?: CommandArgumentDefinition[]): Record<string, string>;
22
+ //# sourceMappingURL=args-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args-parser.d.ts","sourceRoot":"","sources":["../../src/input/args-parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAEzE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CACtB,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,CAAC,EAAE,yBAAyB,EAAE,GACtC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkCxB"}
@@ -0,0 +1,52 @@
1
+ import { InvalidArgumentsError } from '../errors.js';
2
+ /**
3
+ * Parse an array of tokens into a record of `--name value` pairs.
4
+ *
5
+ * - `--name value` produces `{ name: "value" }`
6
+ * - `--flag` (no next token or next token starts with `--`) produces
7
+ * `{ flag: "true" }` (boolean-shorthand)
8
+ * - When `argDefs` is provided, tokens not starting with `--` are
9
+ * matched against argument definitions with a `position` index
10
+ * and consumed in position order.
11
+ *
12
+ * @param tokens - Tokens remaining after command matching.
13
+ * @param argDefs - Optional argument definitions; those with a
14
+ * `position` field are treated as positional (bare token) args.
15
+ * @returns A record mapping argument names (without `--` prefix) to
16
+ * their string values.
17
+ * @throws {InvalidArgumentsError} When a token does not start with
18
+ * `--` (and no positional definition matches), or an empty `--`
19
+ * is encountered.
20
+ */
21
+ export function parseFlags(tokens, argDefs) {
22
+ const args = {};
23
+ const positionalDefs = (argDefs ?? [])
24
+ .filter((d) => d.position !== undefined)
25
+ .sort((a, b) => a.position - b.position);
26
+ let positionalIdx = 0;
27
+ for (let i = 0; i < tokens.length; i++) {
28
+ const token = tokens[i];
29
+ if (!token.startsWith('--')) {
30
+ if (positionalIdx < positionalDefs.length) {
31
+ args[positionalDefs[positionalIdx].name] = token;
32
+ positionalIdx++;
33
+ continue;
34
+ }
35
+ throw new InvalidArgumentsError(`Unexpected token "${token}", expected --argument`);
36
+ }
37
+ const name = token.slice(2);
38
+ if (name.length === 0) {
39
+ throw new InvalidArgumentsError('Empty argument name (--)');
40
+ }
41
+ const next = tokens[i + 1];
42
+ if (next !== undefined && !next.startsWith('--')) {
43
+ args[name] = next;
44
+ i++;
45
+ }
46
+ else {
47
+ args[name] = 'true';
48
+ }
49
+ }
50
+ return args;
51
+ }
52
+ //# sourceMappingURL=args-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args-parser.js","sourceRoot":"","sources":["../../src/input/args-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGrD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,UAAU,CACtB,MAAgB,EAChB,OAAqC;IAErC,MAAM,IAAI,GAA2B,EAAE,CAAC;IACxC,MAAM,cAAc,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;SACjC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC;SACvC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAS,GAAG,CAAC,CAAC,QAAS,CAAC,CAAC;IAC/C,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;QAEzB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,IAAI,aAAa,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC;gBACxC,IAAI,CAAC,cAAc,CAAC,aAAa,CAAE,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;gBAClD,aAAa,EAAE,CAAC;gBAChB,SAAS;YACb,CAAC;YACD,MAAM,IAAI,qBAAqB,CAAC,qBAAqB,KAAK,wBAAwB,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,qBAAqB,CAAC,0BAA0B,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;YAClB,CAAC,EAAE,CAAC;QACR,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;QACxB,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Split a raw input line into tokens, respecting single and double quotes.
3
+ * Leading and trailing whitespace is trimmed; empty or whitespace-only
4
+ * input produces an empty array.
5
+ *
6
+ * Quoted segments are treated as a single token (quotes stripped).
7
+ * Both quote types support `\` escapes and are treated identically.
8
+ * Adjacent non-whitespace characters around quotes are rejected.
9
+ *
10
+ * @param input - Raw input string from the terminal.
11
+ * @throws {ParseError} When quotes are unclosed or adjacent to non-whitespace.
12
+ */
13
+ export declare function tokenize(input: string): string[];
14
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/input/parser.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA0DhD"}
@@ -0,0 +1,65 @@
1
+ import { ParseError } from '../errors.js';
2
+ /**
3
+ * Split a raw input line into tokens, respecting single and double quotes.
4
+ * Leading and trailing whitespace is trimmed; empty or whitespace-only
5
+ * input produces an empty array.
6
+ *
7
+ * Quoted segments are treated as a single token (quotes stripped).
8
+ * Both quote types support `\` escapes and are treated identically.
9
+ * Adjacent non-whitespace characters around quotes are rejected.
10
+ *
11
+ * @param input - Raw input string from the terminal.
12
+ * @throws {ParseError} When quotes are unclosed or adjacent to non-whitespace.
13
+ */
14
+ export function tokenize(input) {
15
+ const trimmed = input.trim();
16
+ if (trimmed.length === 0)
17
+ return [];
18
+ const tokens = [];
19
+ let current = '';
20
+ let inQuote = null;
21
+ for (let i = 0; i < trimmed.length; i++) {
22
+ const ch = trimmed[i];
23
+ if (inQuote && ch === '\\' && i + 1 < trimmed.length) {
24
+ current += trimmed[++i];
25
+ continue;
26
+ }
27
+ if (ch === '"' || ch === "'") {
28
+ if (inQuote === null && current.length > 0) {
29
+ throw new ParseError(`Unexpected characters before quote: "${current}"`);
30
+ }
31
+ if (inQuote === ch) {
32
+ inQuote = null;
33
+ tokens.push(current);
34
+ current = '';
35
+ const next = trimmed[i + 1];
36
+ if (next !== undefined && !/\s/.test(next)) {
37
+ throw new ParseError(`Unexpected character "${next}" after closing quote`);
38
+ }
39
+ continue;
40
+ }
41
+ if (inQuote === null) {
42
+ inQuote = ch;
43
+ continue;
44
+ }
45
+ current += ch;
46
+ continue;
47
+ }
48
+ if (/\s/.test(ch) && inQuote === null) {
49
+ if (current.length > 0) {
50
+ tokens.push(current);
51
+ current = '';
52
+ }
53
+ continue;
54
+ }
55
+ current += ch;
56
+ }
57
+ if (current.length > 0) {
58
+ tokens.push(current);
59
+ }
60
+ if (inQuote !== null) {
61
+ throw new ParseError(`Unclosed ${inQuote} quote`);
62
+ }
63
+ return tokens;
64
+ }
65
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/input/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAa;IAClC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,OAAO,GAAqB,IAAI,CAAC;IAErC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;QAEvB,IAAI,OAAO,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YACnD,OAAO,IAAI,OAAO,CAAC,EAAE,CAAC,CAAE,CAAC;YACzB,SAAS;QACb,CAAC;QAED,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAC3B,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzC,MAAM,IAAI,UAAU,CAAC,wCAAwC,OAAO,GAAG,CAAC,CAAC;YAC7E,CAAC;YACD,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;gBACjB,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACrB,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC5B,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACzC,MAAM,IAAI,UAAU,CAAC,yBAAyB,IAAI,uBAAuB,CAAC,CAAC;gBAC/E,CAAC;gBACD,SAAS;YACb,CAAC;YACD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACnB,OAAO,GAAG,EAAE,CAAC;gBACb,SAAS;YACb,CAAC;YACD,OAAO,IAAI,EAAE,CAAC;YACd,SAAS;QACb,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACpC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACrB,OAAO,GAAG,EAAE,CAAC;YACjB,CAAC;YACD,SAAS;QACb,CAAC;QAED,OAAO,IAAI,EAAE,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,UAAU,CAAC,YAAY,OAAO,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { Hook } from './hook.js';
2
+ import type { Command, CommandContext } from './types.js';
3
+ import type { CommandArguments } from './command-arguments.js';
4
+ type HookRegistrations = {
5
+ beforeParse: (fn: (input: string) => string | Promise<string>) => Hook;
6
+ afterParse: (fn: (tokens: string[]) => string[] | Promise<string[]>) => Hook;
7
+ beforeExecute: (fn: (command: Command, ctx: CommandContext, args: CommandArguments) => void | false | Promise<void | false>) => Hook;
8
+ afterExecute: (fn: (result: unknown) => void | Promise<void>) => Hook;
9
+ beforeExit: (fn: () => void | Promise<void>) => Hook;
10
+ onError: (fn: (error: Error) => void | boolean | Promise<void | boolean>) => Hook;
11
+ };
12
+ declare class HookBuilder<T extends (...args: any[]) => any> {
13
+ private _reg;
14
+ constructor(_reg: (fn: T) => Hook);
15
+ do(callback: T): Hook;
16
+ }
17
+ /**
18
+ * Entry point for registering terminal lifecycle hooks.
19
+ *
20
+ * Created by calling {@link Terminal.hook}. Select an event with one of the
21
+ * selector methods, then call {@link do} to register the callback.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const h = term.hook()
26
+ * .beforeExecute()
27
+ * .do((command) => console.log(command.name()));
28
+ * // later: h.dispose();
29
+ * ```
30
+ */
31
+ export declare class TerminalHookBuilder {
32
+ private _regs;
33
+ constructor(_regs: HookRegistrations);
34
+ beforeParse(): HookBuilder<(input: string) => string | Promise<string>>;
35
+ afterParse(): HookBuilder<(tokens: string[]) => string[] | Promise<string[]>>;
36
+ beforeExecute(): HookBuilder<(command: Command, ctx: CommandContext, args: CommandArguments) => void | false | Promise<void | false>>;
37
+ afterExecute(): HookBuilder<(result: unknown) => void | Promise<void>>;
38
+ beforeExit(): HookBuilder<() => void | Promise<void>>;
39
+ onError(): HookBuilder<(error: Error) => void | boolean | Promise<void | boolean>>;
40
+ }
41
+ export {};
42
+ //# sourceMappingURL=terminal-hook-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-hook-builder.d.ts","sourceRoot":"","sources":["../src/terminal-hook-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,KAAK,iBAAiB,GAAG;IACrB,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IACvE,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7E,aAAa,EAAE,CACX,EAAE,EAAE,CACA,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,gBAAgB,KACrB,IAAI,GAAG,KAAK,GAAG,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,KACxC,IAAI,CAAC;IACV,YAAY,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;IACtE,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;IACrD,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC;CACrF,CAAC;AAEF,cAAM,WAAW,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;IACnC,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI;IACzC,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI;CAGxB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,mBAAmB;IAChB,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,iBAAiB;IAE5C,WAAW,IAAI,WAAW,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAIvE,UAAU,IAAI,WAAW,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAI7E,aAAa,IAAI,WAAW,CACxB,CACI,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,gBAAgB,KACrB,IAAI,GAAG,KAAK,GAAG,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,CAC5C;IAID,YAAY,IAAI,WAAW,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAItE,UAAU,IAAI,WAAW,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAIrD,OAAO,IAAI,WAAW,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;CAGrF"}