@matter/cli-tool 0.11.0-alpha.0-20241013-d38e934bb

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 (66) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +1 -0
  3. package/bin/matter.js +3 -0
  4. package/dist/esm/cli.js +19 -0
  5. package/dist/esm/cli.js.map +6 -0
  6. package/dist/esm/commands/cat.js +17 -0
  7. package/dist/esm/commands/cat.js.map +6 -0
  8. package/dist/esm/commands/cd.js +23 -0
  9. package/dist/esm/commands/cd.js.map +6 -0
  10. package/dist/esm/commands/cwd.js +16 -0
  11. package/dist/esm/commands/cwd.js.map +6 -0
  12. package/dist/esm/commands/help.js +11 -0
  13. package/dist/esm/commands/help.js.map +6 -0
  14. package/dist/esm/commands/index.js +13 -0
  15. package/dist/esm/commands/index.js.map +6 -0
  16. package/dist/esm/commands/ls.js +179 -0
  17. package/dist/esm/commands/ls.js.map +6 -0
  18. package/dist/esm/commands/rm.js +21 -0
  19. package/dist/esm/commands/rm.js.map +6 -0
  20. package/dist/esm/commands/set.js +28 -0
  21. package/dist/esm/commands/set.js.map +6 -0
  22. package/dist/esm/domain.js +178 -0
  23. package/dist/esm/domain.js.map +6 -0
  24. package/dist/esm/errors.js +54 -0
  25. package/dist/esm/errors.js.map +6 -0
  26. package/dist/esm/globals.js +28 -0
  27. package/dist/esm/globals.js.map +6 -0
  28. package/dist/esm/location.js +149 -0
  29. package/dist/esm/location.js.map +6 -0
  30. package/dist/esm/package.json +12 -0
  31. package/dist/esm/parser.js +174 -0
  32. package/dist/esm/parser.js.map +6 -0
  33. package/dist/esm/providers/endpoint.js +38 -0
  34. package/dist/esm/providers/endpoint.js.map +6 -0
  35. package/dist/esm/providers/index.js +9 -0
  36. package/dist/esm/providers/index.js.map +6 -0
  37. package/dist/esm/providers/model.js +40 -0
  38. package/dist/esm/providers/model.js.map +6 -0
  39. package/dist/esm/providers/module.js +26 -0
  40. package/dist/esm/providers/module.js.map +6 -0
  41. package/dist/esm/repl.js +134 -0
  42. package/dist/esm/repl.js.map +6 -0
  43. package/dist/esm/stat.js +63 -0
  44. package/dist/esm/stat.js.map +6 -0
  45. package/package.json +69 -0
  46. package/src/cli.ts +21 -0
  47. package/src/commands/cat.ts +19 -0
  48. package/src/commands/cd.ts +28 -0
  49. package/src/commands/cwd.ts +18 -0
  50. package/src/commands/help.ts +14 -0
  51. package/src/commands/index.ts +13 -0
  52. package/src/commands/ls.ts +232 -0
  53. package/src/commands/rm.ts +25 -0
  54. package/src/commands/set.ts +32 -0
  55. package/src/domain.ts +221 -0
  56. package/src/errors.ts +54 -0
  57. package/src/globals.ts +29 -0
  58. package/src/location.ts +193 -0
  59. package/src/parser.ts +254 -0
  60. package/src/providers/endpoint.ts +44 -0
  61. package/src/providers/index.ts +9 -0
  62. package/src/providers/model.ts +45 -0
  63. package/src/providers/module.ts +30 -0
  64. package/src/repl.ts +168 -0
  65. package/src/stat.ts +121 -0
  66. package/src/tsconfig.json +27 -0
@@ -0,0 +1,232 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2024 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { bin } from "#globals.js";
8
+ import { Location } from "#location.js";
9
+ import colors from "ansi-colors";
10
+ import { stdout } from "process";
11
+ import yargs from "yargs";
12
+
13
+ bin.ls = async function (...rawArgs: unknown[]) {
14
+ const args = await yargs(rawArgs.map(arg => `${arg}`))
15
+ .usage("Show available objects (objects in the current path by default)")
16
+ .option("l", { type: "boolean", description: "use a long listing format" })
17
+ .exitProcess(false)
18
+ .parse();
19
+
20
+ const locations = Array<DisplayLocation>();
21
+ for (const str of args._) {
22
+ const input = `${str}`;
23
+ locations.push(DisplayLocation(await this.location.at(input), input));
24
+ }
25
+
26
+ const files = Array<DisplayLocation>();
27
+ const dirs = Array<DisplayLocation>();
28
+
29
+ if (locations.length) {
30
+ for (const location of locations) {
31
+ if (location.kind === "directory") {
32
+ dirs.push(location);
33
+ } else {
34
+ files.push(location);
35
+ }
36
+ }
37
+ } else {
38
+ for (const basename of await this.location.paths) {
39
+ files.push(DisplayLocation(await this.location.at(basename)));
40
+ }
41
+ }
42
+
43
+ let displayedSomething = false;
44
+
45
+ if (files.length) {
46
+ display(files, "");
47
+ displayedSomething = true;
48
+ }
49
+
50
+ for (const dir of dirs) {
51
+ if (displayedSomething) {
52
+ stdout.write("\n");
53
+ }
54
+ let linePrefix;
55
+ if (displayedSomething || dirs.length > 1) {
56
+ stdout.write(`${dir.displayName ?? dir.basename}:\n`);
57
+ linePrefix = " ";
58
+ } else {
59
+ linePrefix = "";
60
+ }
61
+ display(
62
+ (await Promise.all((await dir.paths).map(path => dir.at(path)))).map(location => DisplayLocation(location)),
63
+ linePrefix,
64
+ );
65
+ }
66
+
67
+ function display(files: DisplayLocation[], linePrefix: string) {
68
+ if (args.l) {
69
+ displayList(files, linePrefix);
70
+ } else {
71
+ const { grid, colWidth } = gridFor(files, linePrefix);
72
+ displayGrid(grid, colWidth, linePrefix);
73
+ }
74
+ }
75
+
76
+ function displayList(files: DisplayLocation[], linePrefix: string) {
77
+ for (const location of files) {
78
+ const { name, length } = formatName(location);
79
+
80
+ let charsAvailable = stdout.columns ?? 80;
81
+
82
+ const { name: longName, tag } = location;
83
+
84
+ stdout.write(linePrefix);
85
+ stdout.write(name);
86
+ stdout.write(" ");
87
+ stdout.write(colors.dim(tag));
88
+ charsAvailable -= length + tag.length + linePrefix.length + 1;
89
+
90
+ let { id, summary } = location;
91
+
92
+ if (id !== undefined) {
93
+ id = `#${id}`;
94
+ stdout.write(colors.dim(id));
95
+ charsAvailable -= id.length + 1;
96
+ }
97
+
98
+ if (longName) {
99
+ stdout.write(' "');
100
+ stdout.write(colors.cyan(longName));
101
+ stdout.write('"');
102
+ charsAvailable -= longName.length + 3;
103
+ }
104
+
105
+ if (summary !== undefined && charsAvailable > 10) {
106
+ stdout.write(" ");
107
+ charsAvailable -= 1;
108
+
109
+ summary = summary.split("\n")[0].trim();
110
+ if (summary.length > charsAvailable) {
111
+ summary = summary.slice(0, charsAvailable - 1) + "…";
112
+ }
113
+
114
+ stdout.write(summary);
115
+ }
116
+ stdout.write("\n");
117
+ }
118
+ }
119
+
120
+ function gridFor(files: DisplayLocation[], linePrefix: string) {
121
+ const columns = (stdout.columns ?? 80) - linePrefix.length;
122
+
123
+ // Maximum width of columns + 1 for special char and +2 for between columns
124
+ const maxWidth = maxWidthOf(files) + 3;
125
+
126
+ let colCount = Math.floor(columns / maxWidth);
127
+ if (colCount === 0) {
128
+ colCount = 1;
129
+ }
130
+
131
+ const rowCount = Math.ceil(files.length / colCount);
132
+
133
+ const grid = Array<DisplayLocation[]>();
134
+
135
+ for (let i = 0; i < files.length; i++) {
136
+ const colNum = Math.floor(i / rowCount);
137
+ const rowNum = i - colNum * rowCount;
138
+ (grid[rowNum] ??= [])[colNum] = files[i];
139
+ }
140
+
141
+ const colWidth = Math.floor(columns / colCount);
142
+
143
+ return { grid, colWidth };
144
+ }
145
+
146
+ function displayGrid(grid: Array<DisplayLocation[]>, colWidth: number, linePrefix: string) {
147
+ for (const row of grid) {
148
+ stdout.write(linePrefix);
149
+ for (const location of row) {
150
+ const { name, length } = formatName(location);
151
+ stdout.write(name);
152
+ stdout.write("".padStart(colWidth - length));
153
+ }
154
+ stdout.write("\n");
155
+ }
156
+ }
157
+
158
+ function formatName(location: DisplayLocation) {
159
+ const name = location.displayName ?? location.basename;
160
+ const length = name.length;
161
+
162
+ if (location.kind === "directory") {
163
+ return { name: `${colors.blue(name)}/`, length: length + 1 };
164
+ }
165
+
166
+ if (location.kind === "command") {
167
+ return { name: `${colors.green(name)}*`, length: length + 1 };
168
+ }
169
+
170
+ return { name, length };
171
+ }
172
+
173
+ function maxWidthOf(locations: DisplayLocation[]) {
174
+ return Math.max(...locations.map(file => (file.displayName ?? file.basename).length));
175
+ }
176
+ };
177
+
178
+ export interface DisplayLocation extends Location {
179
+ displayName: string;
180
+ }
181
+
182
+ function DisplayLocation(location: Location, displayName?: string): DisplayLocation {
183
+ return {
184
+ get kind() {
185
+ return location.kind;
186
+ },
187
+
188
+ get basename() {
189
+ return location.basename;
190
+ },
191
+
192
+ get name() {
193
+ return location.name;
194
+ },
195
+
196
+ get id() {
197
+ return location.id;
198
+ },
199
+
200
+ get path() {
201
+ return location.path;
202
+ },
203
+
204
+ get paths() {
205
+ return location.paths;
206
+ },
207
+
208
+ get tag() {
209
+ return location.tag;
210
+ },
211
+
212
+ get summary() {
213
+ return location.summary;
214
+ },
215
+
216
+ get definition() {
217
+ return location.definition;
218
+ },
219
+
220
+ get displayName() {
221
+ return displayName ?? location.basename;
222
+ },
223
+
224
+ get at() {
225
+ return location.at;
226
+ },
227
+
228
+ get maybeAt() {
229
+ return location.maybeAt;
230
+ },
231
+ };
232
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2024 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { InvalidArgumentError } from "#errors.js";
8
+ import { bin } from "#globals.js";
9
+ import { Location } from "#location.js";
10
+
11
+ bin.rm = async function (...paths: unknown[]) {
12
+ const toDelete = Array<Location>();
13
+
14
+ for (const path of paths) {
15
+ const location = await this.location.at(`${path}`);
16
+ if (!location.parent) {
17
+ throw new InvalidArgumentError(`Invalid argument: Can't delete ${location.path}`);
18
+ }
19
+ toDelete.push(location);
20
+ }
21
+
22
+ for (const location of toDelete) {
23
+ delete (location.parent!.definition as Record<string, unknown>)[location.basename];
24
+ }
25
+ };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2024 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { InvalidArgumentError, TooManyArgsError } from "#errors.js";
8
+ import { bin } from "#globals.js";
9
+ import { Environment, VariableService } from "@matter/general";
10
+
11
+ bin.set = function (keyOrAssignment: unknown, value: unknown) {
12
+ switch (arguments.length) {
13
+ case 0:
14
+ return Environment.default.vars.vars;
15
+
16
+ case 1:
17
+ const assignment = `${keyOrAssignment}`;
18
+ const equalPos = assignment.indexOf("=");
19
+ if (equalPos === -1) {
20
+ throw new InvalidArgumentError(`Invalid argument: parameter must be of the form key=value`);
21
+ }
22
+ Environment.default.vars.set(assignment.slice(0, equalPos), assignment.slice(equalPos + 1));
23
+ break;
24
+
25
+ case 2:
26
+ Environment.default.vars.set(`${keyOrAssignment}`, value as VariableService.Value);
27
+ break;
28
+
29
+ default:
30
+ throw new TooManyArgsError("set");
31
+ }
32
+ };
package/src/domain.ts ADDED
@@ -0,0 +1,221 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2024 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { BadCommandError, IncompleteError, NotACommandError, NotADirectoryError, NotFoundError } from "#errors.js";
8
+ import { InternalError, MaybePromise } from "#general";
9
+ import { bin, globals as defaultGlobals } from "#globals.js";
10
+ import { Location } from "#location.js";
11
+ import { parseInput } from "#parser.js";
12
+ import { Directory } from "#stat.js";
13
+ import { createContext, runInContext, RunningCodeOptions } from "vm";
14
+
15
+ export interface Domain {
16
+ location: Location;
17
+ execute(input: string): Promise<unknown>;
18
+ }
19
+
20
+ /**
21
+ * Maintains state and executes commands.
22
+ */
23
+ export function Domain(): Domain {
24
+ const hiddenGlobals = Object.keys(globalThis);
25
+
26
+ const globals: Record<string, unknown> = Object.defineProperties(
27
+ {},
28
+ {
29
+ ...Object.getOwnPropertyDescriptors(globalThis),
30
+ ...Object.getOwnPropertyDescriptors(defaultGlobals),
31
+ bin: { value: { ...bin }, enumerable: true, writable: false, configurable: false },
32
+ },
33
+ );
34
+
35
+ globals.global = globals.globalThis = globals;
36
+
37
+ const domain: Domain = {
38
+ location: Location(
39
+ "",
40
+ globals,
41
+ Directory({
42
+ paths() {
43
+ const result = new Set(Object.keys(globals));
44
+ for (const name of hiddenGlobals) {
45
+ result.delete(name);
46
+ }
47
+ return [...result];
48
+ },
49
+
50
+ definitionAt(path: string) {
51
+ // Crypto has specialized constraints on its "this"
52
+ if (path === "crypto") {
53
+ return globalThis.crypto;
54
+ }
55
+ return globals[path];
56
+ },
57
+ }),
58
+ undefined,
59
+ ),
60
+
61
+ async execute(inputStr: string) {
62
+ const input = parseInput(inputStr);
63
+
64
+ switch (input.kind) {
65
+ case "empty":
66
+ return;
67
+
68
+ case "incomplete":
69
+ throw new IncompleteError(input.error);
70
+
71
+ case "command":
72
+ break;
73
+
74
+ case "statement":
75
+ return await evaluate(input.js);
76
+
77
+ default:
78
+ throw new InternalError(`Unknown internal command type ${(input as any).kind}`);
79
+ }
80
+
81
+ const { name, args } = input;
82
+
83
+ let location;
84
+ try {
85
+ location = await this.location.at(name);
86
+ } catch (e) {
87
+ if ((e instanceof NotFoundError || e instanceof NotADirectoryError) && name.indexOf("/") === -1) {
88
+ // "path" search
89
+ try {
90
+ location = await this.location.at(Location.join("/bin", name));
91
+ } catch (e2) {
92
+ if (e instanceof NotFoundError || e instanceof NotADirectoryError) {
93
+ // Throw original error
94
+ throw e;
95
+ }
96
+ throw e2;
97
+ }
98
+ } else {
99
+ throw e;
100
+ }
101
+ }
102
+
103
+ const fn = location?.definition;
104
+
105
+ if (location === undefined || fn === undefined) {
106
+ throw new NotACommandError(name);
107
+ }
108
+
109
+ if (typeof fn !== "function") {
110
+ if (args.length) {
111
+ // If there are arguments it must be a call; otherwise it's just inspection
112
+ throw new BadCommandError(name);
113
+ }
114
+ return fn;
115
+ }
116
+
117
+ const argvals = args.map(arg => {
118
+ return evaluate(arg.js, {
119
+ lineOffset: arg.line - 1,
120
+ columnOffset: arg.column,
121
+ });
122
+ });
123
+
124
+ let scope = location.parent?.definition ?? globals;
125
+ if (scope === globals.bin) {
126
+ scope = this;
127
+ }
128
+
129
+ return fn.apply(scope, argvals);
130
+ },
131
+ };
132
+
133
+ const context = createContext(
134
+ new Proxy(
135
+ {},
136
+ {
137
+ get(_target, key, _receiver) {
138
+ if (!(typeof key === "string")) {
139
+ return;
140
+ }
141
+ const value = domain.location.maybeAt(key);
142
+
143
+ if (MaybePromise.is(value)) {
144
+ return value.then(value => {
145
+ if (value === undefined) {
146
+ return globals[key];
147
+ }
148
+ return value.definition;
149
+ });
150
+ }
151
+
152
+ if (value === undefined) {
153
+ return globals[key];
154
+ }
155
+
156
+ return value.definition;
157
+ },
158
+
159
+ set(target, key, newValue, _receiver) {
160
+ const { definition } = domain.location;
161
+ if (definition === undefined || definition === null) {
162
+ // Shouldn't happen
163
+ return false;
164
+ }
165
+ target = definition;
166
+ (target as any)[key] = newValue;
167
+ return true;
168
+ },
169
+
170
+ has(_target, key) {
171
+ const { definition } = domain.location;
172
+ if (definition === undefined || definition === null || typeof definition !== "object") {
173
+ // Shouldn't happen
174
+ return false;
175
+ }
176
+ return key in definition;
177
+ },
178
+
179
+ defineProperty(_target, property, attributes) {
180
+ Object.defineProperty(domain.location.definition, property, attributes);
181
+ return true;
182
+ },
183
+
184
+ deleteProperty(_target, property) {
185
+ const { definition } = domain.location;
186
+ if (definition === undefined || definition === null) {
187
+ // Shouldn't happen
188
+ return false;
189
+ }
190
+ Reflect.deleteProperty(definition, property);
191
+ return true;
192
+ },
193
+
194
+ ownKeys(_target) {
195
+ return [
196
+ ...new Set([...Reflect.ownKeys(globals), ...Reflect.ownKeys(domain.location.definition as {})]),
197
+ ];
198
+ },
199
+
200
+ getOwnPropertyDescriptor(_target, p) {
201
+ const descriptor = Reflect.getOwnPropertyDescriptor(domain.location.definition as {}, p);
202
+ if (descriptor) {
203
+ return descriptor;
204
+ }
205
+ return Reflect.getOwnPropertyDescriptor(globals, p);
206
+ },
207
+ },
208
+ ),
209
+ );
210
+
211
+ return domain;
212
+
213
+ function evaluate(js: string, options: RunningCodeOptions = {}) {
214
+ return runInContext(js, context, {
215
+ breakOnSigint: true,
216
+ filename: "matter-cli-eval",
217
+ displayErrors: false,
218
+ ...options,
219
+ });
220
+ }
221
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2024 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { MatterError } from "#general";
8
+
9
+ export class CliError extends MatterError {
10
+ // Error class won't be the same across vm contexts so make detection easier
11
+ isCliError = true;
12
+ }
13
+
14
+ export class NotFoundError extends CliError {
15
+ constructor(what: unknown) {
16
+ super(`Not found: ${what}`);
17
+ }
18
+ }
19
+
20
+ export class NotADirectoryError extends CliError {
21
+ constructor(what: unknown) {
22
+ super(`Not a directory: ${what}`);
23
+ }
24
+ }
25
+
26
+ export class BadCommandError extends CliError {
27
+ constructor(what: unknown) {
28
+ super(`Bad command: ${what}`);
29
+ }
30
+ }
31
+
32
+ export class NotACommandError extends CliError {
33
+ constructor(what: unknown) {
34
+ super(`Not a command: ${what}`);
35
+ }
36
+ }
37
+
38
+ export class TooManyArgsError extends CliError {
39
+ constructor(what: string) {
40
+ super(`Too many arguments: ${what}`);
41
+ }
42
+ }
43
+
44
+ export class InvalidArgumentError extends CliError {}
45
+
46
+ /**
47
+ * Thrown when statement appears incomplete and REPL should wait for more input.
48
+ */
49
+ export class IncompleteError extends Error {
50
+ constructor(cause: Error) {
51
+ super(cause.message, { cause });
52
+ this.cause = cause;
53
+ }
54
+ }
package/src/globals.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2024 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { Domain } from "#domain.js";
8
+ import * as general from "#general";
9
+ import * as model from "#model";
10
+ import { Matter as matter } from "#model";
11
+ import * as node from "#node";
12
+ import * as protocol from "#protocol";
13
+ import * as tools from "#tools";
14
+ import * as types from "#types";
15
+
16
+ export type GlobalCommand = (this: Domain, ...args: unknown[]) => unknown;
17
+
18
+ export const bin: Record<string, GlobalCommand> = {};
19
+
20
+ export const globals: Record<string, unknown> = {
21
+ general,
22
+ tools,
23
+ protocol,
24
+ node,
25
+ types,
26
+ matter,
27
+ model,
28
+ bin,
29
+ };