Skip to content

Commit ea75093

Browse files
authored
docs: update for 0.38 (#233)
1 parent 634af83 commit ea75093

File tree

4 files changed

+121
-12
lines changed

4 files changed

+121
-12
lines changed

README.md

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Cross platform shell tools for Deno inspired by [zx](https://github.com/google/z
1212
- Makes more code work on Windows.
1313
- Allows exporting the shell's environment to the current process.
1414
- Uses [deno_task_shell](https://github.com/denoland/deno_task_shell)'s parser.
15+
- Has common commands built-in for better Windows support.
1516
1. Minimal globals or global configuration.
1617
- Only a default instance of `$`, but it's not mandatory to use this.
1718
1. No custom CLI.
@@ -27,8 +28,8 @@ import $ from "https://deno.land/x/dax/mod.ts";
2728
// run a command
2829
await $`echo 5`; // outputs: 5
2930

30-
// more complex example outputting 1 to stdout and 2 to stderr
31-
await $`echo 1 && deno eval 'console.error(2);'`;
31+
// outputting 1 to stdout and running a sub process
32+
await $`echo 1 && deno run main.ts`;
3233

3334
// parallel
3435
await Promise.all([
@@ -57,8 +58,8 @@ console.log(result.prop); // 5
5758
Get the result of stdout as bytes (makes stdout "quiet"):
5859

5960
```ts
60-
const result = await $`echo 'test'`.bytes();
61-
console.log(result); // Uint8Array(5) [ 116, 101, 115, 116, 10 ]
61+
const bytes = await $`gzip < file.txt`.bytes();
62+
console.log(bytes);
6263
```
6364

6465
Get the result of stdout as a list of lines (makes stdout "quiet"):
@@ -106,12 +107,31 @@ Piping to a `WritableStream`:
106107
await $`echo 1`.stdout(Deno.stderr.writable, { preventClose: true });
107108
```
108109

109-
Or to a file:
110+
To a file path:
110111

111112
```ts
112113
await $`echo 1`.stdout($.path("data.txt"));
113114
```
114115

116+
To a file:
117+
118+
```ts
119+
using file = $.path("data.txt").openSync({ write: true, create: true });
120+
await $`echo 1`.stdout(file);
121+
```
122+
123+
From one command to another:
124+
125+
```ts
126+
const output = await $`echo foo && echo bar`
127+
.pipe($`grep foo`)
128+
.text();
129+
130+
// or using a pipe sequence
131+
const output = await $`echo foo && echo bar | grep foo`
132+
.text();
133+
```
134+
115135
### Providing arguments to a command
116136

117137
Use an expression in a template literal to provide a single argument to a command:
@@ -159,6 +179,37 @@ const finalText = await $`echo ${result}`.text();
159179
console.log(finalText); // 1
160180
```
161181

182+
#### JavaScript objects to redirects
183+
184+
You can also provide JavaScript objects to shell output redirects:
185+
186+
```ts
187+
const buffer = new Uint8Array(2);
188+
await $`echo 1 && (echo 2 > ${buffer}) && echo 3`; // 1\n3\n
189+
console.log(buffer); // Uint8Array(2) [ 50, 10 ] (2\n)
190+
```
191+
192+
Supported objects: `Uint8Array`, `PathRef`, `WritableStream`, function that returns a `WritableStream`, any object that implements `[$.symbols.writable](): WritableStream`
193+
194+
Or input redirects:
195+
196+
```ts
197+
// strings
198+
const data = "my data in a string";
199+
const bytes = await $`gzip < ${data}`;
200+
201+
// paths
202+
const path = $.path("file.txt");
203+
const bytes = await $`gzip < ${path}`;
204+
205+
// requests (this example does not make the request until after 5 seconds)
206+
const request = $.request("https://plugins.dprint.dev/info.json")
207+
.showProgress(); // show a progress bar while downloading
208+
const bytes = await $`sleep 5 && gzip < ${request}`.bytes();
209+
```
210+
211+
Supported objects: `string`, `Uint8Array`, `PathRef`, `RequestBuilder`, `ReadableStream`, function that returns a `ReadableStream`, any object that implements `[$.symbols.readable](): ReadableStream`
212+
162213
### Providing stdin
163214

164215
```ts
@@ -670,6 +721,17 @@ console.log(response.code);
670721
console.log(await response.json());
671722
```
672723

724+
Requests can be piped to commands:
725+
726+
```ts
727+
const request = $.request("https://plugins.dprint.dev/info.json");
728+
await $`deno run main.ts`.stdin(request);
729+
730+
// or as a redirect... this sleeps 5 seconds, then makes
731+
// request and redirects the output to the command
732+
await $`sleep 5 && deno run main.ts < ${request}`;
733+
```
734+
673735
See the [documentation on `RequestBuilder`](https://deno.land/x/dax/src/request.ts?s=RequestBuilder) for more details. It should be as flexible as `fetch`, but uses a builder API (ex. set headers via `.header(...)`).
674736

675737
### Showing progress
@@ -703,6 +765,25 @@ await $`echo 1 && echo 2`;
703765
await $`echo 1 || echo 2`;
704766
```
705767

768+
Pipe sequences:
769+
770+
```ts
771+
await $`echo 1 | deno run main.ts`;
772+
```
773+
774+
Redirects:
775+
776+
```ts
777+
await $`echo 1 > output.txt`;
778+
const gzippedBytes = await $`gzip < input.txt`.bytes();
779+
```
780+
781+
Sub shells:
782+
783+
```ts
784+
await $`(echo 1 && echo 2) > output.txt`;
785+
```
786+
706787
Setting env var for command in the shell (generally you can just use `.env(...)` though):
707788

708789
```ts

mod.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,12 @@ Deno.test("input redirects with provided object", async () => {
12691269
const output = await $`cat - < ${stream}`.text();
12701270
assertEquals(output, text);
12711271
}
1272+
// string
1273+
{
1274+
const text = "testing".repeat(1000);
1275+
const output = await $`cat - < ${text}`.text();
1276+
assertEquals(output, text);
1277+
}
12721278
// bytes
12731279
{
12741280
const text = "testing".repeat(1000);
@@ -1361,6 +1367,14 @@ Deno.test("output redirect with provided object", async () => {
13611367
await $`echo 1 > ${() => writableStream}`;
13621368
assertEquals(chunks, [new Uint8Array([49, 10])]);
13631369
}
1370+
{
1371+
assertThrows(
1372+
() => $`echo 1 > ${"test.txt"}`,
1373+
Error,
1374+
"Failed resolving expression in command. Cannot provide strings to output " +
1375+
"redirects. Did you mean to provide a path instead via the `$.path(...)` API?",
1376+
);
1377+
}
13641378
});
13651379

13661380
Deno.test("shebang support", async (t) => {

mod.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,15 @@ export type {
7979
*
8080
* Differences:
8181
*
82-
* 1. Minimal globals or global configuration.
83-
* - Only a default instance of `$`, but it's not mandatory to use this.
84-
* 1. No custom CLI.
8582
* 1. Cross platform shell.
8683
* - Makes more code work on Windows.
87-
* - Uses [deno_task_shell](https://github.com/denoland/deno_task_shell)'s parser.
8884
* - Allows exporting the shell's environment to the current process.
89-
* 1. Good for application code in addition to use as a shell script replacement
85+
* - Uses [deno_task_shell](https://github.com/denoland/deno_task_shell)'s parser.
86+
* - Has common commands built-in for better Windows support.
87+
* 1. Minimal globals or global configuration.
88+
* - Only a default instance of `$`, but it's not mandatory to use this.
89+
* 1. No custom CLI.
90+
* 1. Good for application code in addition to use as a shell script replacement.
9091
* 1. Named after my cat.
9192
*
9293
* ## Example

src/command.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,8 +1252,17 @@ function templateInner(
12521252
const expr = exprs[i];
12531253
const inputOrOutputRedirect = detectInputOrOutputRedirect(text);
12541254
if (inputOrOutputRedirect === "<") {
1255-
if (typeof expr === "string" || expr instanceof PathRef) {
1255+
if (expr instanceof PathRef) {
12561256
text += templateLiteralExprToString(expr, escape);
1257+
} else if (typeof expr === "string") {
1258+
handleReadableStream(() =>
1259+
new ReadableStream({
1260+
start(controller) {
1261+
controller.enqueue(new TextEncoder().encode(expr));
1262+
controller.close();
1263+
},
1264+
})
1265+
);
12571266
} else if (expr instanceof ReadableStream) {
12581267
handleReadableStream(() => expr);
12591268
} else if (expr?.[symbols.readable]) {
@@ -1303,7 +1312,7 @@ function templateInner(
13031312
throw new Error("Unsupported object provided to input redirect.");
13041313
}
13051314
} else if (inputOrOutputRedirect === ">") {
1306-
if (typeof expr === "string" || expr instanceof PathRef) {
1315+
if (expr instanceof PathRef) {
13071316
text += templateLiteralExprToString(expr, escape);
13081317
} else if (expr instanceof WritableStream) {
13091318
handleWritableStream(() => expr);
@@ -1349,6 +1358,10 @@ function templateInner(
13491358
);
13501359
}
13511360
});
1361+
} else if (typeof expr === "string") {
1362+
throw new Error(
1363+
"Cannot provide strings to output redirects. Did you mean to provide a path instead via the `$.path(...)` API?",
1364+
);
13521365
} else {
13531366
throw new Error("Unsupported object provided to output redirect.");
13541367
}

0 commit comments

Comments
 (0)