@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.
- package/LICENSE +201 -0
- package/README.md +1 -0
- package/bin/matter.js +3 -0
- package/dist/esm/cli.js +19 -0
- package/dist/esm/cli.js.map +6 -0
- package/dist/esm/commands/cat.js +17 -0
- package/dist/esm/commands/cat.js.map +6 -0
- package/dist/esm/commands/cd.js +23 -0
- package/dist/esm/commands/cd.js.map +6 -0
- package/dist/esm/commands/cwd.js +16 -0
- package/dist/esm/commands/cwd.js.map +6 -0
- package/dist/esm/commands/help.js +11 -0
- package/dist/esm/commands/help.js.map +6 -0
- package/dist/esm/commands/index.js +13 -0
- package/dist/esm/commands/index.js.map +6 -0
- package/dist/esm/commands/ls.js +179 -0
- package/dist/esm/commands/ls.js.map +6 -0
- package/dist/esm/commands/rm.js +21 -0
- package/dist/esm/commands/rm.js.map +6 -0
- package/dist/esm/commands/set.js +28 -0
- package/dist/esm/commands/set.js.map +6 -0
- package/dist/esm/domain.js +178 -0
- package/dist/esm/domain.js.map +6 -0
- package/dist/esm/errors.js +54 -0
- package/dist/esm/errors.js.map +6 -0
- package/dist/esm/globals.js +28 -0
- package/dist/esm/globals.js.map +6 -0
- package/dist/esm/location.js +149 -0
- package/dist/esm/location.js.map +6 -0
- package/dist/esm/package.json +12 -0
- package/dist/esm/parser.js +174 -0
- package/dist/esm/parser.js.map +6 -0
- package/dist/esm/providers/endpoint.js +38 -0
- package/dist/esm/providers/endpoint.js.map +6 -0
- package/dist/esm/providers/index.js +9 -0
- package/dist/esm/providers/index.js.map +6 -0
- package/dist/esm/providers/model.js +40 -0
- package/dist/esm/providers/model.js.map +6 -0
- package/dist/esm/providers/module.js +26 -0
- package/dist/esm/providers/module.js.map +6 -0
- package/dist/esm/repl.js +134 -0
- package/dist/esm/repl.js.map +6 -0
- package/dist/esm/stat.js +63 -0
- package/dist/esm/stat.js.map +6 -0
- package/package.json +69 -0
- package/src/cli.ts +21 -0
- package/src/commands/cat.ts +19 -0
- package/src/commands/cd.ts +28 -0
- package/src/commands/cwd.ts +18 -0
- package/src/commands/help.ts +14 -0
- package/src/commands/index.ts +13 -0
- package/src/commands/ls.ts +232 -0
- package/src/commands/rm.ts +25 -0
- package/src/commands/set.ts +32 -0
- package/src/domain.ts +221 -0
- package/src/errors.ts +54 -0
- package/src/globals.ts +29 -0
- package/src/location.ts +193 -0
- package/src/parser.ts +254 -0
- package/src/providers/endpoint.ts +44 -0
- package/src/providers/index.ts +9 -0
- package/src/providers/model.ts +45 -0
- package/src/providers/module.ts +30 -0
- package/src/repl.ts +168 -0
- package/src/stat.ts +121 -0
- package/src/tsconfig.json +27 -0
package/src/repl.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
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 { IncompleteError } from "#errors.js";
|
|
9
|
+
import { Diagnostic, LogFormat } from "#general";
|
|
10
|
+
import { isCommand } from "#parser.js";
|
|
11
|
+
import colors from "ansi-colors";
|
|
12
|
+
import { homedir } from "os";
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
import { AsyncCompleter, CompleterResult } from "readline";
|
|
15
|
+
import { Recoverable, REPLEval, REPLServer, start } from "repl";
|
|
16
|
+
import "./commands/index.js";
|
|
17
|
+
import "./providers/index.js";
|
|
18
|
+
|
|
19
|
+
// Node.js repl implementation does good stuff for us so want to keep it but we don't want the "." commands and it has
|
|
20
|
+
// no way to disable those. So use this prefix as a hack to prevent it from noticing lines that start with "."
|
|
21
|
+
const LINE_PROTECTOR_CHAR = "\u0001";
|
|
22
|
+
|
|
23
|
+
export async function repl() {
|
|
24
|
+
const domain = Domain();
|
|
25
|
+
|
|
26
|
+
let server: REPLServer | undefined = undefined;
|
|
27
|
+
|
|
28
|
+
const doEval: REPLEval = function (this, evalCmd, _context, _file, cb: (err: Error | null, result: any) => void) {
|
|
29
|
+
// See comment below r.e. "realEmit". We can't just strip first character because the line protector will
|
|
30
|
+
// appear multiple times if there are multiple lines
|
|
31
|
+
evalCmd = evalCmd.replace(new RegExp(LINE_PROTECTOR_CHAR, "g"), "");
|
|
32
|
+
|
|
33
|
+
if (evalCmd.endsWith("\n")) {
|
|
34
|
+
evalCmd = evalCmd.slice(0, evalCmd.length - 1);
|
|
35
|
+
}
|
|
36
|
+
const result: Promise<unknown> = domain.execute(evalCmd);
|
|
37
|
+
result.then(handleSuccess, handleError);
|
|
38
|
+
|
|
39
|
+
function handleSuccess(result: unknown) {
|
|
40
|
+
server?.setPrompt(createPrompt());
|
|
41
|
+
cb(null, result);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function handleError(error: Error) {
|
|
45
|
+
server?.setPrompt(createPrompt());
|
|
46
|
+
|
|
47
|
+
if (error.constructor.name === "IncompleteError") {
|
|
48
|
+
cb(new Recoverable((error as IncompleteError).cause as Error), undefined);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Stack frames following our special matter-cli-* "filenames" are just cruft. And if the first filename
|
|
53
|
+
// then just remove the stack and place location at end of message
|
|
54
|
+
const stack = error.stack;
|
|
55
|
+
if (stack !== undefined) {
|
|
56
|
+
const lines = stack.split("\n");
|
|
57
|
+
let specialLoc: string | undefined;
|
|
58
|
+
let specialLine;
|
|
59
|
+
if ("isCliError" in error) {
|
|
60
|
+
// These are thrown at the top level and should not display a stack trace
|
|
61
|
+
specialLine = 1;
|
|
62
|
+
} else {
|
|
63
|
+
// Look for the "matter-cli-" marker which we prefix on the "filename"
|
|
64
|
+
specialLine = lines.findIndex(line => {
|
|
65
|
+
const match = line.match(/at matter-cli-(?:[a-z]+):([0-9]+:[0-9]+)?/);
|
|
66
|
+
if (match) {
|
|
67
|
+
specialLoc = match[1];
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (specialLine === 1) {
|
|
74
|
+
if (specialLoc) {
|
|
75
|
+
error.message += ` (${specialLoc})`;
|
|
76
|
+
}
|
|
77
|
+
error.stack = `${error.constructor.name}: ${error.message}`;
|
|
78
|
+
} else if (specialLine !== -1) {
|
|
79
|
+
error.stack = lines.slice(0, specialLine + 1).join("\n");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Display the error ourselves so is pretty and captures all details
|
|
84
|
+
const diagnostic = Diagnostic.error(error);
|
|
85
|
+
const formatted = LogFormat[colors.enabled ? "ansi" : "plain"](diagnostic);
|
|
86
|
+
process.stderr.write(`${formatted}\n`);
|
|
87
|
+
|
|
88
|
+
// Do not report the error to node
|
|
89
|
+
cb(null, undefined);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
server = start({
|
|
94
|
+
prompt: createPrompt(),
|
|
95
|
+
eval: doEval,
|
|
96
|
+
ignoreUndefined: true,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const historyPath = process.env.MATTER_REPL_HISTORY || join(homedir(), ".matter-cli-history");
|
|
100
|
+
server.setupHistory(historyPath, error => {
|
|
101
|
+
if (error) {
|
|
102
|
+
console.error(error);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const realEmit = server.emit as (...args: unknown[]) => boolean;
|
|
108
|
+
server.emit = (event, ...args: any[]) => {
|
|
109
|
+
if (event === "line") {
|
|
110
|
+
args[0] = `${LINE_PROTECTOR_CHAR}${args[0]}`;
|
|
111
|
+
}
|
|
112
|
+
return realEmit.call(server, event, ...args);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const complete: AsyncCompleter = (line, callback) => {
|
|
116
|
+
findCompletions(line).then(result => {
|
|
117
|
+
if (result) {
|
|
118
|
+
callback(null, result);
|
|
119
|
+
} else {
|
|
120
|
+
nodeCompleter.call(server, line, callback);
|
|
121
|
+
}
|
|
122
|
+
}, callback);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const nodeCompleter = server.completer;
|
|
126
|
+
Object.defineProperty(server, "completer", { value: complete });
|
|
127
|
+
|
|
128
|
+
function createPrompt() {
|
|
129
|
+
return `${colors.dim("matter")} ${colors.yellow(domain.location.path)} ❯ `;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function findCompletions(line: string): Promise<undefined | CompleterResult> {
|
|
133
|
+
if (line.endsWith("/") ? !isCommand(line.slice(0, line.length - 1)) : !isCommand(line)) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const possiblePath = line.replace(/^.*\s/u, "");
|
|
138
|
+
if (!possiblePath.match(/^[/0-9\p{L}$_%]*$/u)) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const pathsToSearch = Array<string>();
|
|
143
|
+
|
|
144
|
+
const slashPos = possiblePath.lastIndexOf("/");
|
|
145
|
+
let partial;
|
|
146
|
+
if (slashPos === -1) {
|
|
147
|
+
pathsToSearch.push("");
|
|
148
|
+
pathsToSearch.push("/bin");
|
|
149
|
+
partial = possiblePath;
|
|
150
|
+
} else {
|
|
151
|
+
pathsToSearch.push(possiblePath.slice(0, slashPos));
|
|
152
|
+
partial = possiblePath.slice(slashPos + 1);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const completions = Array<string>();
|
|
156
|
+
|
|
157
|
+
for (const path of pathsToSearch) {
|
|
158
|
+
const location = await domain.location.maybeAt(path);
|
|
159
|
+
if (location?.kind !== "directory") {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
completions.push(...(await location.paths).filter(path => path.startsWith(partial)));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return [completions.sort(), partial];
|
|
167
|
+
}
|
|
168
|
+
}
|
package/src/stat.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2024 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { MaybePromise } from "@matter/general";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* An object that does not contain subobjects in our virtual filesystem.
|
|
11
|
+
*/
|
|
12
|
+
export interface File extends Stat.Base {
|
|
13
|
+
kind: "file";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* An object that contains sub-objects in our virtual filesystem.
|
|
18
|
+
*/
|
|
19
|
+
export interface Directory extends Stat.Base {
|
|
20
|
+
kind: "directory";
|
|
21
|
+
paths: MaybePromise<string[]>;
|
|
22
|
+
definitionAt(path: string): MaybePromise<unknown>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function Directory(options: {
|
|
26
|
+
id?: number | string;
|
|
27
|
+
tag?: string;
|
|
28
|
+
name?: string;
|
|
29
|
+
summary?: string;
|
|
30
|
+
paths: () => MaybePromise<string[]>;
|
|
31
|
+
definitionAt: (path: string) => MaybePromise<unknown>;
|
|
32
|
+
}): Directory {
|
|
33
|
+
const { name, summary, id, tag, paths, definitionAt } = options;
|
|
34
|
+
return {
|
|
35
|
+
kind: "directory",
|
|
36
|
+
name,
|
|
37
|
+
summary,
|
|
38
|
+
id,
|
|
39
|
+
tag,
|
|
40
|
+
|
|
41
|
+
get paths() {
|
|
42
|
+
return paths();
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
definitionAt(path: string) {
|
|
46
|
+
return definitionAt(path);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type Stat = File | Directory;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Augments information about "filesystem" locations.
|
|
55
|
+
*/
|
|
56
|
+
export interface StatProvider {
|
|
57
|
+
(definition: unknown): undefined | Stat;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const providers = Array<StatProvider>();
|
|
61
|
+
|
|
62
|
+
export namespace Stat {
|
|
63
|
+
export interface Base {
|
|
64
|
+
name?: string;
|
|
65
|
+
summary?: string;
|
|
66
|
+
id?: number | string;
|
|
67
|
+
tag?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Obtain an Inode for a JS value.
|
|
72
|
+
*/
|
|
73
|
+
export function of(definition: unknown): Stat {
|
|
74
|
+
for (const provider of providers) {
|
|
75
|
+
const stat = provider(definition);
|
|
76
|
+
if (stat) {
|
|
77
|
+
return stat;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (isDirectory(definition)) {
|
|
82
|
+
return {
|
|
83
|
+
kind: "directory",
|
|
84
|
+
|
|
85
|
+
get paths() {
|
|
86
|
+
return Object.keys(definition);
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
definitionAt(path: string) {
|
|
90
|
+
if (path in definition) {
|
|
91
|
+
return definition[path];
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
kind: "file",
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Register a provider.
|
|
104
|
+
*/
|
|
105
|
+
export function provide(provider: StatProvider) {
|
|
106
|
+
providers.push(provider);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Determine if we consider an object a "directory".
|
|
111
|
+
*/
|
|
112
|
+
export function isDirectory(definition: unknown): definition is Record<string, unknown> {
|
|
113
|
+
return (
|
|
114
|
+
typeof definition === "object" &&
|
|
115
|
+
definition !== null &&
|
|
116
|
+
!Array.isArray(definition) &&
|
|
117
|
+
!ArrayBuffer.isView(definition) &&
|
|
118
|
+
!(definition instanceof Date)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tools/tsc/tsconfig.app.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"allowJs": true,
|
|
5
|
+
"types": [
|
|
6
|
+
"globals",
|
|
7
|
+
"node"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
"references": [
|
|
11
|
+
{
|
|
12
|
+
"path": "../../general/src"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"path": "../../model/src"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"path": "../../node/src"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"path": "../../protocol/src"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"path": "../../types/src"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|