Skip to content

Commit

Permalink
prettier: support reading code from stdin (#498)
Browse files Browse the repository at this point in the history
  • Loading branch information
axetroy authored and ry committed Jun 30, 2019
1 parent 9e5473a commit 85db520
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 10 deletions.
15 changes: 12 additions & 3 deletions prettier/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,31 @@ Prettier APIs and tools for deno

To formats the source files, run:

```console
```bash
deno --allow-read --allow-write https://deno.land/std/prettier/main.ts
```

You can format only specific files by passing the arguments.

```console
```bash
deno --allow-read --allow-write https://deno.land/std/prettier/main.ts path/to/script.ts
```

You can format files on specific directory by passing the directory's path.

```console
```bash
deno --allow-read --allow-write https://deno.land/std/prettier/main.ts path/to/script.ts
```

You can format the input plain text stream. default parse it as typescript code.

```bash
cat path/to/script.ts | deno https://deno.land/std/prettier/main.ts
cat path/to/script.js | deno https://deno.land/std/prettier/main.ts --stdin-parser=babel
cat path/to/config.json | deno https://deno.land/std/prettier/main.ts --stdin-parser=json
cat path/to/README.md | deno https://deno.land/std/prettier/main.ts --stdin-parser=markdown
```

## Use API

You can use APIs of prettier as the following:
Expand Down
73 changes: 67 additions & 6 deletions prettier/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
// This script formats the given source files. If the files are omitted, it
// formats the all files in the repository.
const { args, exit, readFile, writeFile, stdout } = Deno;
const { args, exit, readFile, writeFile, stdout, stdin, readAll } = Deno;
import { glob, isGlob, GlobOptions } from "../fs/glob.ts";
import { walk, WalkInfo } from "../fs/walk.ts";
import { parse } from "../flags/mod.ts";
Expand All @@ -41,6 +41,15 @@ Options:
it will output to stdout, Defaults to
false.
--ignore <path> Ignore the given path(s).
--stdin Specifies to read the code from stdin.
If run the command in a pipe, you do not
need to specify this flag.
Defaults to false.
--stdin-parser <typescript|babel|markdown|json>
If set --stdin flag, then need specify a
parser for stdin. available parser:
typescript/babel/markdown/json. Defaults
to typescript.
JS/TS Styling Options:
--print-width <int> The line length where Prettier will try
Expand Down Expand Up @@ -76,6 +85,14 @@ Example:
deno run prettier/main.ts script1.ts
Print the formatted code to stdout
cat script1.ts | deno run prettier/main.ts
Read the typescript code from stdin and
output formatted code to stdout.
cat config.json | deno run prettier/main.ts --stdin-parser=json
Read the JSON string from stdin and
output formatted code to stdout.
`;

// Available parsers
Expand Down Expand Up @@ -237,6 +254,39 @@ async function formatSourceFiles(
exit(0);
}

/**
* Format source code
*/
function format(
text: string,
parser: ParserLabel,
prettierOpts: PrettierOptions
): string {
const formatted: string = prettier.format(text, {
...prettierOpts,
parser: parser,
plugins: prettierPlugins
});

return formatted;
}

/**
* Format code from stdin and output to stdout
*/
async function formatFromStdin(
parser: ParserLabel,
prettierOpts: PrettierOptions
): Promise<void> {
const byte = await readAll(stdin);
const formattedCode = format(
new TextDecoder().decode(byte),
parser,
prettierOpts
);
await stdout.write(new TextEncoder().encode(formattedCode));
}

/**
* Get the files to format.
* @param selectors The glob patterns to select the files.
Expand Down Expand Up @@ -329,14 +379,21 @@ async function main(opts): Promise<void> {
options
);

const tty = Deno.isTTY();

const shouldReadFromStdin =
(!tty.stdin && (tty.stdout || tty.stderr)) || !!opts["stdin"];

try {
if (check) {
if (shouldReadFromStdin) {
await formatFromStdin(opts["stdin-parser"], prettierOpts);
} else if (check) {
await checkSourceFiles(files, prettierOpts);
} else {
await formatSourceFiles(files, prettierOpts);
}
} catch (e) {
console.log(e);
console.error(e);
exit(1);
}
}
Expand All @@ -350,7 +407,8 @@ main(
"trailing-comma",
"arrow-parens",
"prose-wrap",
"end-of-line"
"end-of-line",
"stdin-parser"
],
boolean: [
"check",
Expand All @@ -359,7 +417,8 @@ main(
"use-tabs",
"single-quote",
"bracket-spacing",
"write"
"write",
"stdin"
],
default: {
ignore: [],
Expand All @@ -373,7 +432,9 @@ main(
"arrow-parens": "avoid",
"prose-wrap": "preserve",
"end-of-line": "auto",
write: false
write: false,
stdin: false,
"stdin-parser": "typescript"
},
alias: {
H: "help"
Expand Down
127 changes: 126 additions & 1 deletion prettier/main_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { join } from "../fs/path.ts";
import { EOL } from "../fs/path/constants.ts";
import { assertEquals } from "../testing/asserts.ts";
import { test } from "../testing/mod.ts";
import { test, runIfMain } from "../testing/mod.ts";
import { xrun } from "./util.ts";
import { copy, emptyDir } from "../fs/mod.ts";
const { readAll, execPath } = Deno;
Expand Down Expand Up @@ -233,3 +233,128 @@ test(async function testPrettierPrintToStdout(): Promise<void> {

emptyDir(tempDir);
});

test(async function testPrettierReadFromStdin(): Promise<void> {
interface TestCase {
stdin: string;
stdout: string;
stderr: string;
code: number;
success: boolean;
parser?: string;
}

async function readFromStdinAssertion(
stdin: string,
expectedStdout: string,
expectedStderr: string,
expectedCode: number,
expectedSuccess: boolean,
parser?: string
): Promise<void> {
const inputCode = stdin;
const p1 = Deno.run({
args: [execPath, "./prettier/testdata/echox.ts", `${inputCode}`],
stdout: "piped"
});

const p2 = Deno.run({
args: [
execPath,
"run",
"./prettier/main.ts",
"--stdin",
...(parser ? ["--stdin-parser", parser] : [])
],
stdin: "piped",
stdout: "piped",
stderr: "piped"
});

const n = await Deno.copy(p2.stdin!, p1.stdout!);
assertEquals(n, new TextEncoder().encode(stdin).length);

const status1 = await p1.status();
assertEquals(status1.code, 0);
assertEquals(status1.success, true);
p2.stdin!.close();
const status2 = await p2.status();
assertEquals(status2.code, expectedCode);
assertEquals(status2.success, expectedSuccess);
const decoder = new TextDecoder("utf-8");
assertEquals(
decoder.decode(await Deno.readAll(p2.stdout!)),
expectedStdout
);
assertEquals(
decoder.decode(await Deno.readAll(p2.stderr!)).split(EOL)[0],
expectedStderr
);
p2.close();
p1.close();
}

const testCases: TestCase[] = [
{
stdin: `console.log("abc" )`,
stdout: `console.log("abc");\n`,
stderr: ``,
code: 0,
success: true
},
{
stdin: `console.log("abc" )`,
stdout: `console.log("abc");\n`,
stderr: ``,
code: 0,
success: true,
parser: "babel"
},
{
stdin: `{\"a\":\"b\"}`,
stdout: `{ "a": "b" }\n`,
stderr: ``,
code: 0,
success: true,
parser: "json"
},
{
stdin: `## test`,
stdout: `## test\n`,
stderr: ``,
code: 0,
success: true,
parser: "markdown"
},
{
stdin: `invalid typescript code##!!@@`,
stdout: ``,
stderr: `SyntaxError: ';' expected. (1:9)`,
code: 1,
success: false
},
{
stdin: `console.log("foo");`,
stdout: ``,
stderr:
'Error: Couldn\'t resolve parser "invalid_parser". ' +
"Parsers must be explicitly added to the standalone bundle.",
code: 1,
success: false,
parser: "invalid_parser"
}
];

for (const t of testCases) {
await readFromStdinAssertion(
t.stdin,
t.stdout,
t.stderr,
t.code,
t.success,
t.parser
);
}
});

runIfMain(import.meta);
8 changes: 8 additions & 0 deletions prettier/testdata/echox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
async function echox(args: string[]) {
for (const arg of args) {
await Deno.stdout.write(new TextEncoder().encode(arg));
}
Deno.exit(0);
}

echox(Deno.args.slice(1));

0 comments on commit 85db520

Please sign in to comment.