Repository: prettier/prettier (JavaScript)
Date: 2018-11-08 06:52:14+00:00
Task type: Bug Fix

Issue:
Specifying a flag twice throws an error
<!--

BEFORE SUBMITTING AN ISSUE:

1.  Search for your issue on GitHub: https://github.com/prettier/prettier/issues
    A large number of opened issues are duplicates of existing issues.
    If someone has already opened an issue for what you are experiencing,
    you do not need to open a new issue — please add a 👍 reaction to the
    existing issue instead.

2.  If your issue is with a prettier editor extension or add-on, please open the
    issue in the repo for that extension or add-on, instead of this repo.

-->

**Environments:**
- Prettier Version: 1.15.1
- Running Prettier via: CLI
- Runtime: node 11.1.0
- Operating System: macOS 10.14

**Steps to reproduce:**
```console
$ echo '{"name": "a-package"}' > ./package.json
$ prettier --tab-width 2 --use-tabs --tab-width 4 ./package.json
```

**Expected behavior:**
```console
$ prettier --tab-width 2 --use-tabs --tab-width 4 ./package.json
{
	"name": "a-package"
}
```

**Actual behavior:**
```console
$ prettier --tab-width 2 --use-tabs --tab-width 4 package.json
[error] Invalid --tab-width value. Expected an integer, but received null.
```

---

I happen to find myself in a situation where I need to override a CLI flag with another one, which appended to the invocation later. I cannot just remove the first flag, unfortunately.

What I would expect would be for Prettier to use the last value given for a flag, instead of trying to combine them into an array? (At least, I think that's what `minimist` is doing; I'm not sure where the error about "null" is coming from.)


Issue discussion:

Solution patch:
diff --git a/src/main/options-normalizer.js b/src/main/options-normalizer.js
index c0e3484e34e7..ca9dd2bff70c 100644
--- a/src/main/options-normalizer.js
+++ b/src/main/options-normalizer.js
@@ -158,6 +158,18 @@ function optionInfoToSchema(optionInfo, { isCLI, optionInfos }) {
     handlers.deprecated = true;
   }
 
+  // allow CLI overriding, e.g., prettier package.json --tab-width 1 --tab-width 2
+  if (isCLI && !optionInfo.array) {
+    const originalPreprocess = parameters.preprocess || (x => x);
+    parameters.preprocess = (value, schema, utils) =>
+      schema.preprocess(
+        originalPreprocess(
+          Array.isArray(value) ? value[value.length - 1] : value
+        ),
+        utils
+      );
+  }
+
   return optionInfo.array
     ? vnopts.ArraySchema.create(
         Object.assign(


Test patch:
diff --git a/tests_integration/__tests__/__snapshots__/arg-parsing.js.snap b/tests_integration/__tests__/__snapshots__/arg-parsing.js.snap
index 2ecb96e99471..aed33500032b 100644
--- a/tests_integration/__tests__/__snapshots__/arg-parsing.js.snap
+++ b/tests_integration/__tests__/__snapshots__/arg-parsing.js.snap
@@ -1,5 +1,9 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`allow overriding flags (stderr) 1`] = `""`;
+
+exports[`allow overriding flags (write) 1`] = `Array []`;
+
 exports[`boolean flags do not swallow the next argument (stderr) 1`] = `""`;
 
 exports[`boolean flags do not swallow the next argument (stdout) 1`] = `
diff --git a/tests_integration/__tests__/arg-parsing.js b/tests_integration/__tests__/arg-parsing.js
index 36420e2d1779..31291aa44179 100644
--- a/tests_integration/__tests__/arg-parsing.js
+++ b/tests_integration/__tests__/arg-parsing.js
@@ -37,3 +37,14 @@ describe("deprecated option values are warned", () => {
     status: 0
   });
 });
+
+describe("allow overriding flags", () => {
+  runPrettier(
+    "cli/arg-parsing",
+    ["--tab-width=1", "--tab-width=3", "--parser=babylon"],
+    { input: "function a() { b }" }
+  ).test({
+    stdout: "function a() {\n   b;\n}\n",
+    status: 0
+  });
+});