@venn-lang/io 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.
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
- package/src/actions/console-actions.ts +62 -0
- package/src/index.ts +5 -0
- package/src/plugin.ts +17 -0
- package/src/port/index.ts +3 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vinicius Borges
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# @venn-lang/io
|
|
2
|
+
|
|
3
|
+
> The `io` namespace: standard output, standard error, standard input and the process arguments.
|
|
4
|
+
|
|
5
|
+
A Venn file is a program as often as it is a suite, and a program talks to the outside world through
|
|
6
|
+
its console. This plugin names the parts of it that need naming, on top of the `Console` port. Plain
|
|
7
|
+
`print` is in the prelude and needs no import; everything else is here.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
`@venn-lang/io` is part of the stdlib the `venn` CLI and the language server load, so there is nothing to
|
|
12
|
+
install. A file that uses it says so:
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
use "venn/io"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The plugin declares `requires: ["io"]`. A host that offers no console (the Web Worker host behind
|
|
19
|
+
the editor offers `fs`, `clock`, `random`, `secrets` and `log`) refuses it at load time with
|
|
20
|
+
`VN2010`, rather than failing with a `TypeError` halfway through a run.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
# greet.vn, run with `venn run greet.vn Ada`
|
|
26
|
+
use "venn/io"
|
|
27
|
+
|
|
28
|
+
const argv = io.args
|
|
29
|
+
io.print "arguments: ${argv}"
|
|
30
|
+
|
|
31
|
+
io.write "name? "
|
|
32
|
+
const name = io.readLine
|
|
33
|
+
if name == null {
|
|
34
|
+
io.eprint "no name on standard input"
|
|
35
|
+
exit 1
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
io.print "hello, ${name}"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Verbs
|
|
42
|
+
|
|
43
|
+
| Verb | Signature | What it does |
|
|
44
|
+
| --- | --- | --- |
|
|
45
|
+
| `io.print` | `(...dynamic) -> void` | Writes to standard output with a newline. The same as the prelude's `print`. |
|
|
46
|
+
| `io.write` | `(dynamic) -> void` | Writes to standard output with nothing added after it. |
|
|
47
|
+
| `io.eprint` | `(dynamic) -> void` | Writes to standard error, followed by a newline. |
|
|
48
|
+
| `io.readLine` | `() -> string \| null` | The next line of standard input, or `null` at end of input. |
|
|
49
|
+
| `io.args` | `() -> list<string>` | The command-line arguments passed to the script. |
|
|
50
|
+
|
|
51
|
+
`io.print` takes as many values as you like and joins them with a space. Strings are written as
|
|
52
|
+
they are; anything else is rendered as JSON, so a map never prints as `[object Object]`.
|
|
53
|
+
|
|
54
|
+
`readLine` returns a union with `null` in its signature, not a bare `string`: end of input is a real
|
|
55
|
+
answer and a caller has to face it. `args` returns a `list<string>` rather than a bare list, so
|
|
56
|
+
`argv.len` and the rest of the list methods type correctly.
|
|
57
|
+
|
|
58
|
+
Arguments reach `io.args` from the command line: `venn run greet.vn Ada` gives `["Ada"]`.
|
|
59
|
+
|
|
60
|
+
## The Console port
|
|
61
|
+
|
|
62
|
+
The verbs above are a thin layer over one port, which lives in
|
|
63
|
+
[`@venn-lang/contracts`](../contracts) because a console is a host capability like the filesystem or the
|
|
64
|
+
clock, not something this plugin owns.
|
|
65
|
+
|
|
66
|
+
| | |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| Id | `venn.port.console` |
|
|
69
|
+
| Version | `1` |
|
|
70
|
+
| Requires | `io` |
|
|
71
|
+
| Methods | `write`, `writeError`, `readLine`, `args` |
|
|
72
|
+
|
|
73
|
+
Two implementations ship with it, and both pass the same conformance suite: `createNodeConsole` from
|
|
74
|
+
`@venn-lang/contracts/node`, which writes to Node's real streams and opens stdin lazily on the first
|
|
75
|
+
`readLine`, and `createMemoryConsole`, which records instead of printing and reads from a scripted
|
|
76
|
+
input. `venn run` binds the real one, with the command line's arguments; a test binds the recorder
|
|
77
|
+
and reads back exactly what the program wrote:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { createMemoryConsole } from "@venn-lang/io";
|
|
81
|
+
|
|
82
|
+
const console = createMemoryConsole({ input: ["Ada"], argv: ["--name", "ada"] });
|
|
83
|
+
|
|
84
|
+
console.write(">");
|
|
85
|
+
console.out; // ">"
|
|
86
|
+
await console.readLine(); // "Ada"
|
|
87
|
+
await console.readLine(); // null
|
|
88
|
+
console.args(); // ["--name", "ada"]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## API
|
|
92
|
+
|
|
93
|
+
| Export | What it is |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `ioPlugin` (also the default export) | The `PluginDefinition`: namespace `io`, requires the `io` capability, five actions, no types. |
|
|
96
|
+
| `consoleActions` | The five `ActionDefinition`s, in the order listed above. |
|
|
97
|
+
| `ConsolePort` | The port descriptor, re-exported from `@venn-lang/contracts`. |
|
|
98
|
+
| `Console` | The port's interface (type only). |
|
|
99
|
+
| `createMemoryConsole` | The recording implementation, for tests. |
|
|
100
|
+
|
|
101
|
+
## See also
|
|
102
|
+
|
|
103
|
+
- [`@venn-lang/contracts`](../contracts) for the port, its Node implementation and the host capabilities.
|
|
104
|
+
- [`@venn-lang/fmt`](../std-fmt) for turning a value into the text you print.
|
|
105
|
+
- [`@venn-lang/cli`](../cli) for `venn run`, which binds the real console and passes the arguments in.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ActionDefinition, PluginDefinition } from "@venn-lang/sdk";
|
|
2
|
+
import { Console, ConsolePort, createMemoryConsole } from "@venn-lang/contracts";
|
|
3
|
+
//#region src/actions/console-actions.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The verbs of the `io` namespace: standard output, standard error, standard
|
|
6
|
+
* input and the process arguments.
|
|
7
|
+
*
|
|
8
|
+
* Plain `print` is in the prelude and needs no import. `io.print` is the same
|
|
9
|
+
* verb under its full name, so a script that imports the namespace reads the
|
|
10
|
+
* same either way.
|
|
11
|
+
*/
|
|
12
|
+
declare const consoleActions: ActionDefinition[];
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/plugin.d.ts
|
|
15
|
+
/**
|
|
16
|
+
* The `io` plugin: a script's standard input, standard output and arguments.
|
|
17
|
+
*
|
|
18
|
+
* Requires the host capability `io`. Where the host has no real console streams
|
|
19
|
+
* the plugin refuses to load with a readable diagnostic, rather than failing
|
|
20
|
+
* mid-run.
|
|
21
|
+
*/
|
|
22
|
+
declare const ioPlugin: PluginDefinition;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { type Console, ConsolePort, consoleActions, createMemoryConsole, ioPlugin as default, ioPlugin };
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/actions/console-actions.ts","../src/plugin.ts"],"mappings":";;;;;;;;;;;cA2Ba,gBAAgB;;;;;;;;;;cCjBhB,UAAU"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { arg, defineAction, definePlugin, restArg } from "@venn-lang/sdk";
|
|
2
|
+
import { t } from "@venn-lang/types";
|
|
3
|
+
import { ConsolePort, createMemoryConsole } from "@venn-lang/contracts";
|
|
4
|
+
//#region src/actions/console-actions.ts
|
|
5
|
+
/** How a printed value becomes text: strings as-is, everything else as JSON. */
|
|
6
|
+
function display(value) {
|
|
7
|
+
if (typeof value === "string") return value;
|
|
8
|
+
if (value === null || typeof value !== "object") return String(value);
|
|
9
|
+
try {
|
|
10
|
+
return JSON.stringify(value);
|
|
11
|
+
} catch {
|
|
12
|
+
return String(value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function line(args) {
|
|
16
|
+
return args.map(display).join(" ");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The verbs of the `io` namespace: standard output, standard error, standard
|
|
20
|
+
* input and the process arguments.
|
|
21
|
+
*
|
|
22
|
+
* Plain `print` is in the prelude and needs no import. `io.print` is the same
|
|
23
|
+
* verb under its full name, so a script that imports the namespace reads the
|
|
24
|
+
* same either way.
|
|
25
|
+
*/
|
|
26
|
+
const consoleActions = [
|
|
27
|
+
defineAction({
|
|
28
|
+
name: "print",
|
|
29
|
+
doc: "Write to standard output with a newline. Same as the prelude's `print`.",
|
|
30
|
+
args: [restArg("values", t.dynamic, "Anything, as many as you like.")],
|
|
31
|
+
result: t.void,
|
|
32
|
+
run: (ctx, input) => ctx.port(ConsolePort).write(`${line(input.args)}\n`)
|
|
33
|
+
}),
|
|
34
|
+
defineAction({
|
|
35
|
+
name: "write",
|
|
36
|
+
doc: "Write to standard output with no trailing newline.",
|
|
37
|
+
args: [arg("value", t.dynamic, "What to write. Nothing is added after it.")],
|
|
38
|
+
result: t.void,
|
|
39
|
+
run: (ctx, input) => ctx.port(ConsolePort).write(line(input.args))
|
|
40
|
+
}),
|
|
41
|
+
defineAction({
|
|
42
|
+
name: "eprint",
|
|
43
|
+
doc: "Write to standard error, followed by a newline.",
|
|
44
|
+
args: [arg("value", t.dynamic, "What to write to stderr.")],
|
|
45
|
+
result: t.void,
|
|
46
|
+
run: (ctx, input) => ctx.port(ConsolePort).writeError(`${line(input.args)}\n`)
|
|
47
|
+
}),
|
|
48
|
+
defineAction({
|
|
49
|
+
name: "readLine",
|
|
50
|
+
doc: "Read the next line from standard input, or null at end of input.",
|
|
51
|
+
result: t.union(t.string, t.null),
|
|
52
|
+
run: (ctx) => ctx.port(ConsolePort).readLine()
|
|
53
|
+
}),
|
|
54
|
+
defineAction({
|
|
55
|
+
name: "args",
|
|
56
|
+
doc: "The command-line arguments passed to the script.",
|
|
57
|
+
result: t.list(t.string),
|
|
58
|
+
run: (ctx) => [...ctx.port(ConsolePort).args()]
|
|
59
|
+
})
|
|
60
|
+
];
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/plugin.ts
|
|
63
|
+
/**
|
|
64
|
+
* The `io` plugin: a script's standard input, standard output and arguments.
|
|
65
|
+
*
|
|
66
|
+
* Requires the host capability `io`. Where the host has no real console streams
|
|
67
|
+
* the plugin refuses to load with a readable diagnostic, rather than failing
|
|
68
|
+
* mid-run.
|
|
69
|
+
*/
|
|
70
|
+
const ioPlugin = definePlugin({
|
|
71
|
+
name: "venn/io",
|
|
72
|
+
version: "0.0.0",
|
|
73
|
+
namespace: "io",
|
|
74
|
+
requires: ["io"],
|
|
75
|
+
actions: consoleActions
|
|
76
|
+
});
|
|
77
|
+
//#endregion
|
|
78
|
+
export { ConsolePort, consoleActions, createMemoryConsole, ioPlugin as default, ioPlugin };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/actions/console-actions.ts","../src/plugin.ts"],"sourcesContent":["import { type ActionDefinition, arg, defineAction, restArg } from \"@venn-lang/sdk\";\nimport { t } from \"@venn-lang/types\";\nimport { ConsolePort } from \"../port/index.js\";\n\n/** How a printed value becomes text: strings as-is, everything else as JSON. */\nfunction display(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (value === null || typeof value !== \"object\") return String(value);\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction line(args: readonly unknown[]): string {\n return args.map(display).join(\" \");\n}\n\n/**\n * The verbs of the `io` namespace: standard output, standard error, standard\n * input and the process arguments.\n *\n * Plain `print` is in the prelude and needs no import. `io.print` is the same\n * verb under its full name, so a script that imports the namespace reads the\n * same either way.\n */\nexport const consoleActions: ActionDefinition[] = [\n defineAction({\n name: \"print\",\n doc: \"Write to standard output with a newline. Same as the prelude's `print`.\",\n args: [restArg(\"values\", t.dynamic, \"Anything, as many as you like.\")],\n result: t.void,\n run: (ctx, input) => ctx.port(ConsolePort).write(`${line(input.args)}\\n`),\n }),\n defineAction({\n name: \"write\",\n doc: \"Write to standard output with no trailing newline.\",\n args: [arg(\"value\", t.dynamic, \"What to write. Nothing is added after it.\")],\n result: t.void,\n run: (ctx, input) => ctx.port(ConsolePort).write(line(input.args)),\n }),\n defineAction({\n name: \"eprint\",\n doc: \"Write to standard error, followed by a newline.\",\n args: [arg(\"value\", t.dynamic, \"What to write to stderr.\")],\n result: t.void,\n run: (ctx, input) => ctx.port(ConsolePort).writeError(`${line(input.args)}\\n`),\n }),\n defineAction({\n name: \"readLine\",\n doc: \"Read the next line from standard input, or null at end of input.\",\n result: t.union(t.string, t.null),\n run: (ctx) => ctx.port(ConsolePort).readLine(),\n }),\n defineAction({\n name: \"args\",\n doc: \"The command-line arguments passed to the script.\",\n result: t.list(t.string),\n run: (ctx) => [...ctx.port(ConsolePort).args()],\n }),\n];\n","import { definePlugin, type PluginDefinition } from \"@venn-lang/sdk\";\nimport { consoleActions } from \"./actions/console-actions.js\";\n\n/**\n * The `io` plugin: a script's standard input, standard output and arguments.\n *\n * Requires the host capability `io`. Where the host has no real console streams\n * the plugin refuses to load with a readable diagnostic, rather than failing\n * mid-run.\n */\nexport const ioPlugin: PluginDefinition = definePlugin({\n name: \"venn/io\",\n version: \"0.0.0\",\n namespace: \"io\",\n requires: [\"io\"],\n actions: consoleActions,\n});\n"],"mappings":";;;;;AAKA,SAAS,QAAQ,OAAwB;CACvC,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU,OAAO,OAAO,KAAK;CACpE,IAAI;EACF,OAAO,KAAK,UAAU,KAAK;CAC7B,QAAQ;EACN,OAAO,OAAO,KAAK;CACrB;AACF;AAEA,SAAS,KAAK,MAAkC;CAC9C,OAAO,KAAK,IAAI,OAAO,CAAC,CAAC,KAAK,GAAG;AACnC;;;;;;;;;AAUA,MAAa,iBAAqC;CAChD,aAAa;EACX,MAAM;EACN,KAAK;EACL,MAAM,CAAC,QAAQ,UAAU,EAAE,SAAS,gCAAgC,CAAC;EACrE,QAAQ,EAAE;EACV,MAAM,KAAK,UAAU,IAAI,KAAK,WAAW,CAAC,CAAC,MAAM,GAAG,KAAK,MAAM,IAAI,EAAE,GAAG;CAC1E,CAAC;CACD,aAAa;EACX,MAAM;EACN,KAAK;EACL,MAAM,CAAC,IAAI,SAAS,EAAE,SAAS,2CAA2C,CAAC;EAC3E,QAAQ,EAAE;EACV,MAAM,KAAK,UAAU,IAAI,KAAK,WAAW,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC;CACnE,CAAC;CACD,aAAa;EACX,MAAM;EACN,KAAK;EACL,MAAM,CAAC,IAAI,SAAS,EAAE,SAAS,0BAA0B,CAAC;EAC1D,QAAQ,EAAE;EACV,MAAM,KAAK,UAAU,IAAI,KAAK,WAAW,CAAC,CAAC,WAAW,GAAG,KAAK,MAAM,IAAI,EAAE,GAAG;CAC/E,CAAC;CACD,aAAa;EACX,MAAM;EACN,KAAK;EACL,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI;EAChC,MAAM,QAAQ,IAAI,KAAK,WAAW,CAAC,CAAC,SAAS;CAC/C,CAAC;CACD,aAAa;EACX,MAAM;EACN,KAAK;EACL,QAAQ,EAAE,KAAK,EAAE,MAAM;EACvB,MAAM,QAAQ,CAAC,GAAG,IAAI,KAAK,WAAW,CAAC,CAAC,KAAK,CAAC;CAChD,CAAC;AACH;;;;;;;;;;ACnDA,MAAa,WAA6B,aAAa;CACrD,MAAM;CACN,SAAS;CACT,WAAW;CACX,UAAU,CAAC,IAAI;CACf,SAAS;AACX,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@venn-lang/io",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The io namespace: standard output, standard error, standard input and the process arguments.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"venn",
|
|
7
|
+
"testing",
|
|
8
|
+
"e2e",
|
|
9
|
+
"io"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/venn-lang/venn/tree/main/packages/std-io#readme",
|
|
12
|
+
"bugs": "https://github.com/venn-lang/venn/issues",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/venn-lang/venn.git",
|
|
16
|
+
"directory": "packages/std-io"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Vinicius Borges",
|
|
20
|
+
"type": "module",
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"development": "./src/index.ts",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.js",
|
|
27
|
+
"default": "./dist/index.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"src",
|
|
33
|
+
"!src/**/*.test.ts",
|
|
34
|
+
"!src/**/*.suite.ts"
|
|
35
|
+
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@venn-lang/contracts": "0.1.0",
|
|
41
|
+
"@venn-lang/sdk": "0.1.0",
|
|
42
|
+
"@venn-lang/types": "0.1.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@fast-check/vitest": "^0.4.1",
|
|
46
|
+
"tsdown": "^0.22.14",
|
|
47
|
+
"typescript": "^7.0.2",
|
|
48
|
+
"vitest": "^4.1.10"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsdown",
|
|
52
|
+
"test": "vitest run",
|
|
53
|
+
"typecheck": "tsc --noEmit"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type ActionDefinition, arg, defineAction, restArg } from "@venn-lang/sdk";
|
|
2
|
+
import { t } from "@venn-lang/types";
|
|
3
|
+
import { ConsolePort } from "../port/index.js";
|
|
4
|
+
|
|
5
|
+
/** How a printed value becomes text: strings as-is, everything else as JSON. */
|
|
6
|
+
function display(value: unknown): string {
|
|
7
|
+
if (typeof value === "string") return value;
|
|
8
|
+
if (value === null || typeof value !== "object") return String(value);
|
|
9
|
+
try {
|
|
10
|
+
return JSON.stringify(value);
|
|
11
|
+
} catch {
|
|
12
|
+
return String(value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function line(args: readonly unknown[]): string {
|
|
17
|
+
return args.map(display).join(" ");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The verbs of the `io` namespace: standard output, standard error, standard
|
|
22
|
+
* input and the process arguments.
|
|
23
|
+
*
|
|
24
|
+
* Plain `print` is in the prelude and needs no import. `io.print` is the same
|
|
25
|
+
* verb under its full name, so a script that imports the namespace reads the
|
|
26
|
+
* same either way.
|
|
27
|
+
*/
|
|
28
|
+
export const consoleActions: ActionDefinition[] = [
|
|
29
|
+
defineAction({
|
|
30
|
+
name: "print",
|
|
31
|
+
doc: "Write to standard output with a newline. Same as the prelude's `print`.",
|
|
32
|
+
args: [restArg("values", t.dynamic, "Anything, as many as you like.")],
|
|
33
|
+
result: t.void,
|
|
34
|
+
run: (ctx, input) => ctx.port(ConsolePort).write(`${line(input.args)}\n`),
|
|
35
|
+
}),
|
|
36
|
+
defineAction({
|
|
37
|
+
name: "write",
|
|
38
|
+
doc: "Write to standard output with no trailing newline.",
|
|
39
|
+
args: [arg("value", t.dynamic, "What to write. Nothing is added after it.")],
|
|
40
|
+
result: t.void,
|
|
41
|
+
run: (ctx, input) => ctx.port(ConsolePort).write(line(input.args)),
|
|
42
|
+
}),
|
|
43
|
+
defineAction({
|
|
44
|
+
name: "eprint",
|
|
45
|
+
doc: "Write to standard error, followed by a newline.",
|
|
46
|
+
args: [arg("value", t.dynamic, "What to write to stderr.")],
|
|
47
|
+
result: t.void,
|
|
48
|
+
run: (ctx, input) => ctx.port(ConsolePort).writeError(`${line(input.args)}\n`),
|
|
49
|
+
}),
|
|
50
|
+
defineAction({
|
|
51
|
+
name: "readLine",
|
|
52
|
+
doc: "Read the next line from standard input, or null at end of input.",
|
|
53
|
+
result: t.union(t.string, t.null),
|
|
54
|
+
run: (ctx) => ctx.port(ConsolePort).readLine(),
|
|
55
|
+
}),
|
|
56
|
+
defineAction({
|
|
57
|
+
name: "args",
|
|
58
|
+
doc: "The command-line arguments passed to the script.",
|
|
59
|
+
result: t.list(t.string),
|
|
60
|
+
run: (ctx) => [...ctx.port(ConsolePort).args()],
|
|
61
|
+
}),
|
|
62
|
+
];
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// The `io` namespace: standard input, standard error and process arguments.
|
|
2
|
+
// Plain `print` needs no import: it is in the prelude.
|
|
3
|
+
export { consoleActions } from "./actions/console-actions.js";
|
|
4
|
+
export { ioPlugin, ioPlugin as default } from "./plugin.js";
|
|
5
|
+
export { type Console, ConsolePort, createMemoryConsole } from "./port/index.js";
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { definePlugin, type PluginDefinition } from "@venn-lang/sdk";
|
|
2
|
+
import { consoleActions } from "./actions/console-actions.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The `io` plugin: a script's standard input, standard output and arguments.
|
|
6
|
+
*
|
|
7
|
+
* Requires the host capability `io`. Where the host has no real console streams
|
|
8
|
+
* the plugin refuses to load with a readable diagnostic, rather than failing
|
|
9
|
+
* mid-run.
|
|
10
|
+
*/
|
|
11
|
+
export const ioPlugin: PluginDefinition = definePlugin({
|
|
12
|
+
name: "venn/io",
|
|
13
|
+
version: "0.0.0",
|
|
14
|
+
namespace: "io",
|
|
15
|
+
requires: ["io"],
|
|
16
|
+
actions: consoleActions,
|
|
17
|
+
});
|