Repository: prettier/prettier (JavaScript)
Date: 2020-07-24 09:47:24+00:00
Task type: Feature

Issue:
Implement a new `--ignore-unknown` argument for CLI
Idea - do not throw an error on unknown extensions (when we don’t know which parser should be used)

Why? For tools like `lint-staged`. 

Main idea:

```js
{
  "*.*": "prettier --write --ignore-unknown"
}
```

This will avoid listing extensions. 

We already support `prettier --list-different .` and it improves 0CJS configuration, now we can do it more.

/cc @prettier/core your thoughts?


Issue discussion:
As mentioned in #8454, another use case where this can be very useful:

```bash
onchange . -- prettier --write --ignore-unknown '{{changed}}'
```

Solution patch:
diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml
index 83519e34a39b..ac74494a227e 100644
--- a/.pre-commit-hooks.yaml
+++ b/.pre-commit-hooks.yaml
@@ -1,16 +1,4 @@
 - id: prettier
   name: prettier
-  entry: prettier --write --list-different
+  entry: prettier --write --list-different --ignore-unknown
   language: node
-  files: "\\.(\
-    css|less|scss\
-    |graphql|gql\
-    |html\
-    |js|jsx\
-    |json\
-    |md|markdown|mdown|mkdn\
-    |mdx\
-    |ts|tsx\
-    |vue\
-    |yaml|yml\
-    )$"
diff --git a/changelog_unreleased/cli/pr-8829.md b/changelog_unreleased/cli/pr-8829.md
new file mode 100644
index 000000000000..1d81c3806513
--- /dev/null
+++ b/changelog_unreleased/cli/pr-8829.md
@@ -0,0 +1,14 @@
+#### Added `--ignore-unknown`(alias `-u`) flag ([#8829](https://github.com/prettier/prettier/pull/8829) by [@fisker](https://github.com/fisker))
+
+```console
+# Prettier stable
+npx prettier * --check
+Checking formatting...
+foo.unknown[error] No parser could be inferred for file: foo.unknown
+All matched files use Prettier code style!
+
+# Prettier master
+npx prettier * --check --ignore-unknown
+Checking formatting...
+All matched files use Prettier code style!
+```
diff --git a/docs/cli.md b/docs/cli.md
index 0e48fbb196d9..06f372da952b 100644
--- a/docs/cli.md
+++ b/docs/cli.md
@@ -204,3 +204,11 @@ $ cat abc.css | prettier --stdin-filepath abc.css
   display: none;
 }
 ```
+
+## `--ignore-unknown`
+
+With `--ignore-unknown` (or `-u`), prettier will ignore unknown files matched by patterns.
+
+```console
+$ prettier "**/*" --write --ignore-unknown
+```
diff --git a/docs/install.md b/docs/install.md
index 377662987650..7305e0819be0 100644
--- a/docs/install.md
+++ b/docs/install.md
@@ -103,11 +103,13 @@ For example, you can add the following to your `package.json` to have ESLint and
     }
   },
   "lint-staged": {
-    "**/*": ["eslint --fix", "prettier --write"]
+    "**/*": "prettier --write --ignore-unknown"
   }
 }
 ```
 
+> Note: If you use ESLint, make sure lint-staged runs it before Prettier, not after.
+
 See [Pre-commit Hook](precommit.md) for more information.
 
 ## Summary
diff --git a/docs/precommit.md b/docs/precommit.md
index 123d7279f0a7..24627270f42c 100644
--- a/docs/precommit.md
+++ b/docs/precommit.md
@@ -103,7 +103,7 @@ and add this config to your `package.json`:
 {
   "husky": {
     "hooks": {
-      "pre-commit": "git-format-staged -f 'prettier --stdin --stdin-filepath \"{}\"' ."
+      "pre-commit": "git-format-staged -f 'prettier --ignore-unknown --stdin --stdin-filepath \"{}\"' ."
     }
   }
 }
diff --git a/docs/watching-files.md b/docs/watching-files.md
index fa11f51534bc..b4cb93d70190 100644
--- a/docs/watching-files.md
+++ b/docs/watching-files.md
@@ -6,7 +6,7 @@ title: Watching For Changes
 You can have Prettier watch for changes from the command line by using [onchange](https://www.npmjs.com/package/onchange). For example:
 
 ```bash
-npx onchange '**/*.js' -- npx prettier --write {{changed}}
+npx onchange "**/*" -- npx prettier --write --ignore-unknown {{changed}}
 ```
 
 Or add the following to your `package.json`:
@@ -14,7 +14,7 @@ Or add the following to your `package.json`:
 ```json
 {
   "scripts": {
-    "prettier-watch": "onchange '**/*.js' -- prettier --write {{changed}}"
+    "prettier-watch": "onchange \"**/*\" -- prettier --write --ignore-unknown {{changed}}"
   }
 }
 ```
diff --git a/src/cli/constant.js b/src/cli/constant.js
index dbfe6af33693..7df977e15175 100644
--- a/src/cli/constant.js
+++ b/src/cli/constant.js
@@ -174,6 +174,11 @@ const options = {
     default: ".prettierignore",
     description: "Path to a file with patterns describing files to ignore.",
   },
+  "ignore-unknown": {
+    type: "boolean",
+    alias: "u",
+    description: "Ignore unknown files.",
+  },
   "list-different": {
     type: "boolean",
     category: coreOptions.CATEGORY_OUTPUT,
diff --git a/src/cli/util.js b/src/cli/util.js
index 8f00b446b2ef..ebac557b8f86 100644
--- a/src/cli/util.js
+++ b/src/cli/util.js
@@ -60,10 +60,13 @@ function diff(a, b) {
 
 function handleError(context, filename, error) {
   if (error instanceof errors.UndefinedParserError) {
-    if (context.argv.write && isTTY()) {
+    if ((context.argv.write || context.argv["ignore-unknown"]) && isTTY()) {
       readline.clearLine(process.stdout, 0);
       readline.cursorTo(process.stdout, 0, null);
     }
+    if (context.argv["ignore-unknown"]) {
+      return;
+    }
     if (!context.argv.check && !context.argv["list-different"]) {
       process.exitCode = 2;
     }


Test patch:
diff --git a/tests_integration/__tests__/__snapshots__/early-exit.js.snap b/tests_integration/__tests__/__snapshots__/early-exit.js.snap
index 5472deb7a0e8..39e1ddf60c97 100644
--- a/tests_integration/__tests__/__snapshots__/early-exit.js.snap
+++ b/tests_integration/__tests__/__snapshots__/early-exit.js.snap
@@ -151,6 +151,7 @@ Other options:
                            * inferredParser (string | null) - name of parser inferred from file path
   -h, --help <flag>        Show CLI usage, or details about the given flag.
                            Example: --help write
+  -u, --ignore-unknown     Ignore unknown files.
   --insert-pragma          Insert @format pragma into file's first docblock comment.
                            Defaults to false.
   --loglevel <silent|error|warn|log|debug>
@@ -310,6 +311,7 @@ Other options:
                            * inferredParser (string | null) - name of parser inferred from file path
   -h, --help <flag>        Show CLI usage, or details about the given flag.
                            Example: --help write
+  -u, --ignore-unknown     Ignore unknown files.
   --insert-pragma          Insert @format pragma into file's first docblock comment.
                            Defaults to false.
   --loglevel <silent|error|warn|log|debug>
diff --git a/tests_integration/__tests__/__snapshots__/help-options.js.snap b/tests_integration/__tests__/__snapshots__/help-options.js.snap
index 343e3660114b..c7b4aa3d4b3e 100644
--- a/tests_integration/__tests__/__snapshots__/help-options.js.snap
+++ b/tests_integration/__tests__/__snapshots__/help-options.js.snap
@@ -221,6 +221,17 @@ Default: .prettierignore
 
 exports[`show detailed usage with --help ignore-path (write) 1`] = `Array []`;
 
+exports[`show detailed usage with --help ignore-unknown (stderr) 1`] = `""`;
+
+exports[`show detailed usage with --help ignore-unknown (stdout) 1`] = `
+"-u, --ignore-unknown
+
+  Ignore unknown files.
+"
+`;
+
+exports[`show detailed usage with --help ignore-unknown (write) 1`] = `Array []`;
+
 exports[`show detailed usage with --help insert-pragma (stderr) 1`] = `""`;
 
 exports[`show detailed usage with --help insert-pragma (stdout) 1`] = `
diff --git a/tests_integration/__tests__/__snapshots__/ignore-unknown.js.snap b/tests_integration/__tests__/__snapshots__/ignore-unknown.js.snap
new file mode 100644
index 000000000000..3d563676b538
--- /dev/null
+++ b/tests_integration/__tests__/__snapshots__/ignore-unknown.js.snap
@@ -0,0 +1,69 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Ignored file (stderr) 1`] = `""`;
+
+exports[`Ignored file (stdout) 1`] = `""`;
+
+exports[`Ignored file (write) 1`] = `Array []`;
+
+exports[`None exist file (stderr) 1`] = `
+"[error] No files matching the pattern were found: \\"non-exist-file\\".
+"
+`;
+
+exports[`None exist file (stdout) 1`] = `""`;
+
+exports[`None exist file (write) 1`] = `Array []`;
+
+exports[`Not matching pattern (stderr) 1`] = `
+"[error] No files matching the pattern were found: \\"*.non-exist-pattern\\".
+"
+`;
+
+exports[`Not matching pattern (stdout) 1`] = `""`;
+
+exports[`Not matching pattern (write) 1`] = `Array []`;
+
+exports[`ignore-unknown alias (stdout) 1`] = `
+"javascript.js
+"
+`;
+
+exports[`ignore-unknown check (stderr) 1`] = `
+"[warn] javascript.js
+[warn] Code style issues found in the above file(s). Forgot to run Prettier?
+"
+`;
+
+exports[`ignore-unknown check (stdout) 1`] = `
+"Checking formatting...
+"
+`;
+
+exports[`ignore-unknown check (write) 1`] = `Array []`;
+
+exports[`ignore-unknown dir (stdout) 1`] = `
+"javascript.js
+"
+`;
+
+exports[`ignore-unknown pattern (stdout) 1`] = `
+"javascript.js
+override.as-js-file
+"
+`;
+
+exports[`ignore-unknown write (stdout) 1`] = `
+"javascript.js
+"
+`;
+
+exports[`ignore-unknown write (write) 1`] = `
+Array [
+  Object {
+    "content": "const foo = \\"bar\\";
+",
+    "filename": "javascript.js",
+  },
+]
+`;
diff --git a/tests_integration/__tests__/ignore-unknown.js b/tests_integration/__tests__/ignore-unknown.js
new file mode 100644
index 000000000000..01b5581e23d3
--- /dev/null
+++ b/tests_integration/__tests__/ignore-unknown.js
@@ -0,0 +1,77 @@
+"use strict";
+
+const runPrettier = require("../runPrettier");
+
+describe("ignore-unknown dir", () => {
+  runPrettier("cli/ignore-unknown", [
+    ".",
+    "--ignore-unknown",
+    "--list-different",
+  ]).test({
+    status: "non-zero",
+    stderr: "",
+    write: [],
+  });
+});
+
+describe("ignore-unknown alias", () => {
+  runPrettier("cli/ignore-unknown", [".", "-u", "--list-different"]).test({
+    status: "non-zero",
+    stderr: "",
+    write: [],
+  });
+});
+
+describe("ignore-unknown pattern", () => {
+  runPrettier("cli/ignore-unknown", [
+    "*",
+    "--ignore-unknown",
+    "--list-different",
+  ]).test({
+    status: "non-zero",
+    stderr: "",
+    write: [],
+  });
+});
+
+describe("ignore-unknown write", () => {
+  runPrettier("cli/ignore-unknown", [
+    ".",
+    "--ignore-unknown",
+    "--write",
+    "--list-different",
+  ]).test({
+    status: 0,
+    stderr: "",
+  });
+});
+
+describe("ignore-unknown check", () => {
+  runPrettier("cli/ignore-unknown", [".", "--ignore-unknown", "--check"]).test({
+    status: 1,
+  });
+});
+
+describe("None exist file", () => {
+  runPrettier("cli/ignore-unknown", [
+    "non-exist-file",
+    "--ignore-unknown",
+  ]).test({
+    status: 2,
+  });
+});
+
+describe("Not matching pattern", () => {
+  runPrettier("cli/ignore-unknown", [
+    "*.non-exist-pattern",
+    "--ignore-unknown",
+  ]).test({
+    status: 2,
+  });
+});
+
+describe("Ignored file", () => {
+  runPrettier("cli/ignore-unknown", ["ignored.js", "--ignore-unknown"]).test({
+    status: 0,
+  });
+});
diff --git a/tests_integration/cli/ignore-unknown/.prettierignore b/tests_integration/cli/ignore-unknown/.prettierignore
new file mode 100644
index 000000000000..1615b0c68a90
--- /dev/null
+++ b/tests_integration/cli/ignore-unknown/.prettierignore
@@ -0,0 +1,1 @@
+ignored.js
diff --git a/tests_integration/cli/ignore-unknown/.prettierrc b/tests_integration/cli/ignore-unknown/.prettierrc
new file mode 100644
index 000000000000..df113efb1b0d
--- /dev/null
+++ b/tests_integration/cli/ignore-unknown/.prettierrc
@@ -0,0 +1,10 @@
+{
+  "overrides": [
+    {
+      "files": "*.as-js-file",
+      "options": {
+        "parser": "babel"
+      }
+    }
+  ]
+}
diff --git a/tests_integration/cli/ignore-unknown/ignored.js b/tests_integration/cli/ignore-unknown/ignored.js
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests_integration/cli/ignore-unknown/javascript.js b/tests_integration/cli/ignore-unknown/javascript.js
new file mode 100644
index 000000000000..b02987937a9f
--- /dev/null
+++ b/tests_integration/cli/ignore-unknown/javascript.js
@@ -0,0 +1,1 @@
+const foo=        "bar";
diff --git a/tests_integration/cli/ignore-unknown/override.as-js-file b/tests_integration/cli/ignore-unknown/override.as-js-file
new file mode 100644
index 000000000000..b02987937a9f
--- /dev/null
+++ b/tests_integration/cli/ignore-unknown/override.as-js-file
@@ -0,0 +1,1 @@
+const foo=        "bar";
diff --git a/tests_integration/cli/ignore-unknown/unkown-file-extension.unknown b/tests_integration/cli/ignore-unknown/unkown-file-extension.unknown
new file mode 100644
index 000000000000..e2358dcb5ac4
--- /dev/null
+++ b/tests_integration/cli/ignore-unknown/unkown-file-extension.unknown
@@ -0,0 +1,1 @@
+PRETTIER
diff --git a/tests_integration/cli/ignore-unknown/unkown-filename b/tests_integration/cli/ignore-unknown/unkown-filename
new file mode 100644
index 000000000000..e2358dcb5ac4
--- /dev/null
+++ b/tests_integration/cli/ignore-unknown/unkown-filename
@@ -0,0 +1,1 @@
+PRETTIER