Repository: eslint/eslint (js)

Issue:
`spaced-comment` should allow line ending after markers
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).

    This template is for requesting a rule change. If you are here for another reason, please see below:

    1. To report a bug: https://eslint.org/docs/developer-guide/contributing/reporting-bugs
    2. To propose a new rule: https://eslint.org/docs/developer-guide/contributing/new-rules
    3. To request a change that is not a bug fix, rule change, or new rule: https://eslint.org/docs/developer-guide/contributing/changes
    4. If you have any questions, please stop by our chatroom: https://gitter.im/eslint/eslint

    Note that leaving sections blank will make it difficult for us to troubleshoot and we may have to close the issue.
-->

**What rule do you want to change?**
[spaced-comment](https://eslint.org/docs/rules/spaced-comment)

**Does this change cause the rule to produce more or fewer warnings?**
fewer

**How will the change be implemented? (New option, new default behavior, etc.)?**
default behavior

**Please provide some example code that this change will affect:**

<!-- Put your code examples here -->
```js
/* eslint spaced-comment: ["error", "always", { "line": { "markers": ["/", "#region", "#endregion"] } }] */
/* eslint no-trailing-spaces: ["error"] */

//#region blah
const answer = 42;
//#endregion

console.log(answer);
```

**What does the rule currently do for this code?**

> 6:1  error  Expected space or tab after '//#endregion' in comment  spaced-comment

using `--fix` cannot fix it (since there are no possible auto fix)

**What will the rule do after it's changed?**

pass without tip an error

**Are you willing to submit a pull request to implement this change?**

Maybe no

----

`spaced-comment` does allow line ending after `//` without using markers. And this behavior should be applied to markers too imo.

Pull request:
Fix: ignore marker-only comments in spaced-comment (fixes #12036)
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[X] Bug fix #12036

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**

If the whole comment is equal to any of the specified markers, that comment will be ignored by this rule.

This applies to both line comments and block comments.

**Is there anything you'd like reviewers to focus on?**

This indirectly allows `/***/` and `//*` (`"*"` is always a marker).


Patch:
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 102d47e83..fec55351f 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,1 +1,2 @@
+github: eslint
 open_collective: eslint
diff --git a/docs/rules/camelcase.md b/docs/rules/camelcase.md
index 5c4efcfe4..96135f8c9 100644
--- a/docs/rules/camelcase.md
+++ b/docs/rules/camelcase.md
@@ -13,7 +13,7 @@ This rule has an object option:
 * `"properties": "always"` (default) enforces camelcase style for property names
 * `"properties": "never"` does not check property names
 * `"ignoreDestructuring": false` (default) enforces camelcase style for destructured identifiers
-* `"ignoreDestructuring": true` does not check destructured identifiers
+* `"ignoreDestructuring": true` does not check destructured identifiers (but still checks any use of those identifiers later in the code)
 * `"ignoreImports": false` (default) enforces camelcase style for ES2015 imports
 * `"ignoreImports": true` does not check ES2015 imports (but still checks any use of the imports later in the code except function arguments)
 * `allow` (`string[]`) list of properties to accept. Accept regex.
@@ -154,6 +154,39 @@ var { category_id = 1 } = query;
 var { category_id: category_id } = query;
 ```
 
+Please note that this option applies only to identifiers inside destructuring patterns. It doesn't additionally allow any particular use of the created variables later in the code apart from the use that is already allowed by default or by other options.
+
+Examples of additional **incorrect** code for this rule with the `{ "ignoreDestructuring": true }` option:
+
+```js
+/*eslint camelcase: ["error", {ignoreDestructuring: true}]*/
+
+var { some_property } = obj; // allowed by {ignoreDestructuring: true}
+var foo = some_property + 1; // error, ignoreDestructuring does not apply to this statement
+```
+
+A common use case for this option is to avoid useless renaming when the identifier is not intended to be used later in the code.
+
+Examples of additional **correct** code for this rule with the `{ "ignoreDestructuring": true }` option:
+
+```js
+/*eslint camelcase: ["error", {ignoreDestructuring: true}]*/
+
+var { some_property, ...rest } = obj;
+// do something with 'rest', nothing with 'some_property'
+```
+
+Another common use case for this option is in combination with `{ "properties": "never" }`, when the identifier is intended to be used only as a property shorthand.
+
+Examples of additional **correct** code for this rule with the `{ "properties": "never", "ignoreDestructuring": true }` options:
+
+```js
+/*eslint camelcase: ["error", {"properties": "never", ignoreDestructuring: true}]*/
+
+var { some_property } = obj;
+doSomething({ some_property });
+```
+
 ### ignoreImports: false
 
 Examples of **incorrect** code for this rule with the default `{ "ignoreImports": false }` option:
diff --git a/lib/init/config-initializer.js b/lib/init/config-initializer.js
index 48e56ce52..28dfad194 100644
--- a/lib/init/config-initializer.js
+++ b/lib/init/config-initializer.js
@@ -291,6 +291,7 @@ function processAnswers(answers) {
             jsx: true
         };
         config.plugins = ["react"];
+        config.extends.push("plugin:react/recommended");
     } else if (answers.framework === "vue") {
         config.plugins = ["vue"];
         config.extends.push("plugin:vue/essential");
@@ -522,9 +523,9 @@ function promptUser() {
             name: "styleguide",
             message: "Which style guide do you want to follow?",
             choices: [
-                { name: "Airbnb (https://github.com/airbnb/javascript)", value: "airbnb" },
-                { name: "Standard (https://github.com/standard/standard)", value: "standard" },
-                { name: "Google (https://github.com/google/eslint-config-google)", value: "google" }
+                { name: "Airbnb: https://github.com/airbnb/javascript", value: "airbnb" },
+                { name: "Standard: https://github.com/standard/standard", value: "standard" },
+                { name: "Google: https://github.com/google/eslint-config-google", value: "google" }
             ],
             when(answers) {
                 answers.packageJsonExists = npmUtils.checkPackageJson();
diff --git a/lib/rules/key-spacing.js b/lib/rules/key-spacing.js
index 994c35627..5aced89a6 100644
--- a/lib/rules/key-spacing.js
+++ b/lib/rules/key-spacing.js
@@ -42,6 +42,30 @@ function isSingleLine(node) {
     return (node.loc.end.line === node.loc.start.line);
 }
 
+/**
+ * Checks whether both nodes are on the same line.
+ * @param {ASTNode} nodeA AST Node being evaluated.
+ * @param {ASTNode} nodeB AST Node being evaluated.
+ * @returns {boolean} True if both nodes are on the same line.
+ */
+function isOnSameLine(nodeA, nodeB) {
+    return (nodeA.loc.end.line === nodeB.loc.end.line);
+}
+
+/**
+ * Checks whether the properties of a node on the same line.
+ * @param {ASTNode} node node
+ * @returns {boolean} True if the properties of a node are on the same line.
+ */
+function isPropertiesOnSameLine(node) {
+    if (node.properties.length <= 1) {
+        return true;
+    }
+    const [firstProperty] = node.properties;
+
+    return node.properties.every(property => isOnSameLine(firstProperty, property));
+}
+
 /**
  * Initializes a single option property from the configuration with defaults for undefined values
  * @param {Object} toOptions Object to be initialized
@@ -630,7 +654,7 @@ module.exports = {
 
             return {
                 ObjectExpression(node) {
-                    if (isSingleLine(node)) {
+                    if (isSingleLine(node) || isPropertiesOnSameLine(node)) {
                         verifyListSpacing(node.properties.filter(isKeyValueProperty));
                     } else {
                         verifyAlignment(node);
@@ -643,7 +667,9 @@ module.exports = {
         // Obey beforeColon and afterColon in each property as configured
         return {
             Property(node) {
-                verifySpacing(node, isSingleLine(node.parent) ? singleLineOptions : multiLineOptions);
+                const option = (isSingleLine(node.parent) || isPropertiesOnSameLine(node.parent)) ? singleLineOptions : multiLineOptions;
+
+                verifySpacing(node, option);
             }
         };
 
diff --git a/lib/rules/no-octal-escape.js b/lib/rules/no-octal-escape.js
index 7f6845ec7..5b4c7b2eb 100644
--- a/lib/rules/no-octal-escape.js
+++ b/lib/rules/no-octal-escape.js
@@ -38,7 +38,7 @@ module.exports = {
 
                 // \0 represents a valid NULL character if it isn't followed by a digit.
                 const match = node.raw.match(
-                    /^(?:[^\\]|\\.)*?\\([0-3][0-7]{1,2}|[4-7][0-7]|[1-7])/u
+                    /^(?:[^\\]|\\.)*?\\([0-3][0-7]{1,2}|[4-7][0-7]|0(?=[89])|[1-7])/su
                 );
 
                 if (match) {
diff --git a/lib/rules/spaced-comment.js b/lib/rules/spaced-comment.js
index 958bb2c64..daf56cd6b 100644
--- a/lib/rules/spaced-comment.js
+++ b/lib/rules/spaced-comment.js
@@ -249,7 +249,8 @@ module.exports = {
                 beginRegex: requireSpace ? createAlwaysStylePattern(markers, exceptions) : createNeverStylePattern(markers),
                 endRegex: balanced && requireSpace ? new RegExp(`${createExceptionsPattern(exceptions)}$`, "u") : new RegExp(endNeverPattern, "u"),
                 hasExceptions: exceptions.length > 0,
-                markers: new RegExp(`^(${markers.map(escape).join("|")})`, "u")
+                captureMarker: new RegExp(`^(${markers.map(escape).join("|")})`, "u"),
+                markers: new Set(markers)
             };
 
             return rule;
@@ -322,8 +323,8 @@ module.exports = {
                 rule = styleRules[type],
                 commentIdentifier = type === "block" ? "/*" : "//";
 
-            // Ignores empty comments.
-            if (node.value.length === 0) {
+            // Ignores empty comments and comments that consist only of a marker.
+            if (node.value.length === 0 || rule.markers.has(node.value)) {
                 return;
             }
 
@@ -333,7 +334,7 @@ module.exports = {
             // Checks.
             if (requireSpace) {
                 if (!beginMatch) {
-                    const hasMarker = rule.markers.exec(node.value);
+                    const hasMarker = rule.captureMarker.exec(node.value);
                     const marker = hasMarker ? commentIdentifier + hasMarker[0] : commentIdentifier;
 
                     if (rule.hasExceptions) {


Test patch:
diff --git a/tests/lib/rules/key-spacing.js b/tests/lib/rules/key-spacing.js
index a9ed53374..9225f8b8c 100644
--- a/tests/lib/rules/key-spacing.js
+++ b/tests/lib/rules/key-spacing.js
@@ -384,6 +384,214 @@ ruleTester.run("key-spacing", rule, {
         }],
         parserOptions: { ecmaVersion: 2018 }
     },
+    {
+        code: [
+            "({",
+            "    foo : 1, bar : 2, baz : 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            beforeColon: true
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            beforeColon: false
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            afterColon: true
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo:1, bar:2, baz:3",
+            "});"
+        ].join("\n"),
+        options: [{
+            afterColon: false
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo :1, bar :2, baz :3",
+            "});"
+        ].join("\n"),
+        options: [{
+            beforeColon: true,
+            afterColon: false
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            beforeColon: false,
+            afterColon: true
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo : 1, bar : 2, baz : 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            beforeColon: true,
+            afterColon: true
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo:1, bar:2, baz:3",
+            "});"
+        ].join("\n"),
+        options: [{
+            beforeColon: false,
+            afterColon: false
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            mode: "strict"
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo:  1, bar:  2, baz:  3",
+            "});"
+        ].join("\n"),
+        options: [{
+            mode: "minimum"
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            singleLine: {
+                afterColon: true,
+                beforeColon: false
+            }
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo :1, bar :2, baz :3",
+            "});"
+        ].join("\n"),
+        options: [{
+            singleLine: {
+                afterColon: false,
+                beforeColon: true
+            }
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo: 'bar',",
+            "});"
+        ].join("\n"),
+        options: [{
+            multiLine: {
+                align: "value"
+            }
+        }]
+    },
+    {
+        code: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            multiLine: {
+                align: "value"
+            }
+        }]
+    },
+    {
+        code: [
+            "({",
+            "  foo: 1, bar: { qux: 4",
+            "  }, baz: 3,",
+            "})"
+        ].join("\n"),
+        options: [
+            {
+                singleLine: {
+                    afterColon: true,
+                    beforeColon: false
+                },
+                multiLine: {
+                    align: "value"
+                }
+            }
+        ]
+    },
+    {
+        code: [
+            "({",
+            "  foo: 1, bar: { qux1: 4, qux2: 5",
+            "  }, baz: 3,",
+            "})"
+        ].join("\n"),
+        options: [
+            {
+                singleLine: {
+                    afterColon: true,
+                    beforeColon: false
+                },
+                multiLine: {
+                    align: "value"
+                }
+            }
+        ]
+    },
+    {
+        code: [
+            "({",
+            "  foo: 1, bar: {",
+            "    qux1: 4, qux2: 5",
+            "  }, baz: 3,",
+            "})"
+        ].join("\n"),
+        options: [
+            {
+                multiLine: {
+                    align: "value"
+                }
+            }
+        ]
+    },
 
     // https://github.com/eslint/eslint/issues/4792
     {
@@ -1769,5 +1977,218 @@ ruleTester.run("key-spacing", rule, {
             { messageId: "missingKey", data: { computed: "", key: "foo" }, line: 1, column: 7, type: "Identifier" },
             { messageId: "missingValue", data: { computed: "", key: "foo" }, line: 1, column: 19, type: "Identifier" }
         ]
+    },
+    {
+        code: [
+            "({",
+            "    foo : 1, bar : 2, baz : 3",
+            "});"
+        ].join("\n"),
+        output: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            beforeColon: false
+        }],
+        errors: [
+            { messageId: "extraKey", data: { computed: "", key: "foo" }, line: 2, column: 5, type: "Identifier" },
+            { messageId: "extraKey", data: { computed: "", key: "bar" }, line: 2, column: 14, type: "Identifier" },
+            { messageId: "extraKey", data: { computed: "", key: "baz" }, line: 2, column: 23, type: "Identifier" }
+        ]
+    },
+    {
+        code: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        output: [
+            "({",
+            "    foo : 1, bar : 2, baz : 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            beforeColon: true
+        }],
+        errors: [
+            { messageId: "missingKey", data: { computed: "", key: "foo" }, line: 2, column: 5, type: "Identifier" },
+            { messageId: "missingKey", data: { computed: "", key: "bar" }, line: 2, column: 13, type: "Identifier" },
+            { messageId: "missingKey", data: { computed: "", key: "baz" }, line: 2, column: 21, type: "Identifier" }
+        ]
+    },
+    {
+        code: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        output: [
+            "({",
+            "    foo:1, bar:2, baz:3",
+            "});"
+        ].join("\n"),
+        options: [{
+            afterColon: false
+        }],
+        errors: [
+            { messageId: "extraValue", data: { computed: "", key: "foo" }, line: 2, column: 10, type: "Literal" },
+            { messageId: "extraValue", data: { computed: "", key: "bar" }, line: 2, column: 18, type: "Literal" },
+            { messageId: "extraValue", data: { computed: "", key: "baz" }, line: 2, column: 26, type: "Literal" }
+        ]
+    },
+    {
+        code: [
+            "({",
+            "    foo:1, bar:2, baz:3",
+            "});"
+        ].join("\n"),
+        output: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            afterColon: true
+        }],
+        errors: [
+            { messageId: "missingValue", data: { computed: "", key: "foo" }, line: 2, column: 9, type: "Literal" },
+            { messageId: "missingValue", data: { computed: "", key: "bar" }, line: 2, column: 16, type: "Literal" },
+            { messageId: "missingValue", data: { computed: "", key: "baz" }, line: 2, column: 23, type: "Literal" }
+        ]
+    },
+    {
+        code: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        output: [
+            "({",
+            "    foo :1, bar :2, baz :3",
+            "});"
+        ].join("\n"),
+        options: [{
+            beforeColon: true,
+            afterColon: false
+        }],
+        errors: [
+            { messageId: "missingKey", data: { computed: "", key: "foo" }, line: 2, column: 5, type: "Identifier" },
+            { messageId: "extraValue", data: { computed: "", key: "foo" }, line: 2, column: 10, type: "Literal" },
+            { messageId: "missingKey", data: { computed: "", key: "bar" }, line: 2, column: 13, type: "Identifier" },
+            { messageId: "extraValue", data: { computed: "", key: "bar" }, line: 2, column: 18, type: "Literal" },
+            { messageId: "missingKey", data: { computed: "", key: "baz" }, line: 2, column: 21, type: "Identifier" },
+            { messageId: "extraValue", data: { computed: "", key: "baz" }, line: 2, column: 26, type: "Literal" }
+        ]
+    },
+    {
+        code: [
+            "({",
+            "    foo :1, bar :2, baz :3",
+            "});"
+        ].join("\n"),
+        output: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            mode: "strict"
+        }],
+        errors: [
+            { messageId: "extraKey", data: { computed: "", key: "foo" }, line: 2, column: 5, type: "Identifier" },
+            { messageId: "missingValue", data: { computed: "", key: "foo" }, line: 2, column: 10, type: "Literal" },
+            { messageId: "extraKey", data: { computed: "", key: "bar" }, line: 2, column: 13, type: "Identifier" },
+            { messageId: "missingValue", data: { computed: "", key: "bar" }, line: 2, column: 18, type: "Literal" },
+            { messageId: "extraKey", data: { computed: "", key: "baz" }, line: 2, column: 21, type: "Identifier" },
+            { messageId: "missingValue", data: { computed: "", key: "baz" }, line: 2, column: 26, type: "Literal" }
+        ]
+    },
+    {
+        code: [
+            "({",
+            "    foo :1, bar :2, baz :3",
+            "});"
+        ].join("\n"),
+        output: [
+            "({",
+            "    foo: 1, bar: 2, baz: 3",
+            "});"
+        ].join("\n"),
+        options: [{
+            mode: "minimum"
+        }],
+        errors: [
+            { messageId: "extraKey", data: { computed: "", key: "foo" }, line: 2, column: 5, type: "Identifier" },
+            { messageId: "missingValue", data: { computed: "", key: "foo" }, line: 2, column: 10, type: "Literal" },
+            { messageId: "extraKey", data: { computed: "", key: "bar" }, line: 2, column: 13, type: "Identifier" },
+            { messageId: "missingValue", data: { computed: "", key: "bar" }, line: 2, column: 18, type: "Literal" },
+            { messageId: "extraKey", data: { computed: "", key: "baz" }, line: 2, column: 21, type: "Identifier" },
+            { messageId: "missingValue", data: { computed: "", key: "baz" }, line: 2, column: 26, type: "Literal" }
+        ]
+    },
+    {
+        code: [
+            "({",
+            "    foo: 1, bar: 2,",
+            "});"
+        ].join("\n"),
+        output: [
+            "({",
+            "    foo :1, bar :2,",
+            "});"
+        ].join("\n"),
+        options: [{
+            singleLine: {
+                beforeColon: true,
+                afterColon: false
+            }
+        }],
+        errors: [
+            { messageId: "missingKey", data: { computed: "", key: "foo" }, line: 2, column: 5, type: "Identifier" },
+            { messageId: "extraValue", data: { computed: "", key: "foo" }, line: 2, column: 10, type: "Literal" },
+            { messageId: "missingKey", data: { computed: "", key: "bar" }, line: 2, column: 13, type: "Identifier" },
+            { messageId: "extraValue", data: { computed: "", key: "bar" }, line: 2, column: 18, type: "Literal" }
+        ]
+    },
+    {
+        code: [
+            "({",
+            "  foo: 1, bar: { qux1: 4, qux2: 5",
+            "  }, baz: 3,",
+            "})"
+        ].join("\n"),
+        output: [
+            "({",
+            "  foo :1, bar :{ qux1 :4, qux2 :5",
+            "  }, baz :3,",
+            "})"
+        ].join("\n"),
+        options: [
+            {
+                singleLine: {
+                    afterColon: false,
+                    beforeColon: true
+                },
+                multiLine: {
+                    align: "value",
+                    afterColon: false,
+                    beforeColon: true
+                }
+            }
+        ],
+        errors: [
+            { messageId: "missingKey", data: { computed: "", key: "foo" }, line: 2, column: 3, type: "Identifier" },
+            { messageId: "extraValue", data: { computed: "", key: "foo" }, line: 2, column: 8, type: "Literal" },
+            { messageId: "missingKey", data: { computed: "", key: "bar" }, line: 2, column: 11, type: "Identifier" },
+            { messageId: "extraValue", data: { computed: "", key: "bar" }, line: 2, column: 16, type: "ObjectExpression" },
+            { messageId: "missingKey", data: { computed: "", key: "qux1" }, line: 2, column: 18, type: "Identifier" },
+            { messageId: "extraValue", data: { computed: "", key: "qux1" }, line: 2, column: 24, type: "Literal" },
+            { messageId: "missingKey", data: { computed: "", key: "qux2" }, line: 2, column: 27, type: "Identifier" },
+            { messageId: "extraValue", data: { computed: "", key: "qux2" }, line: 2, column: 33, type: "Literal" },
+            { messageId: "missingKey", data: { computed: "", key: "baz" }, line: 3, column: 6, type: "Identifier" },
+            { messageId: "extraValue", data: { computed: "", key: "baz" }, line: 3, column: 11, type: "Literal" }
+        ]
     }]
 });
diff --git a/tests/lib/rules/no-octal-escape.js b/tests/lib/rules/no-octal-escape.js
index cd555ab60..d89910f86 100644
--- a/tests/lib/rules/no-octal-escape.js
+++ b/tests/lib/rules/no-octal-escape.js
@@ -25,33 +25,107 @@ ruleTester.run("no-octal-escape", rule, {
         "var foo = \"foo \\\\251 bar\";",
         "var foo = /([abc]) \\1/g;",
         "var foo = '\\0';",
+        "'\\0'",
+        "'\\8'",
+        "'\\9'",
         "'\\0 '",
+        "' \\0'",
+        "'a\\0'",
         "'\\0a'",
+        "'a\\8a'",
+        "'\\0\\8'",
+        "'\\8\\0'",
+        "'\\80'",
+        "'\\81'",
+        "'\\\\'",
+        "'\\\\0'",
+        "'\\\\08'",
         "'\\\\1'",
         "'\\\\01'",
-        "'\\08'",
-        "'\\09'"
+        "'\\\\12'",
+        "'\\\\\\0'",
+        "'\\\\\\8'",
+        "'\\0\\\\'",
+        "'0'",
+        "'1'",
+        "'8'",
+        "'01'",
+        "'08'",
+        "'80'",
+        "'12'",
+        "'\\a'",
+        "'\\n'"
     ],
     invalid: [
 
         // Test full message
         { code: "var foo = \"foo \\01 bar\";", errors: [{ message: "Don't use octal: '\\01'. Use '\\u....' instead.", type: "Literal" }] },
 
+        { code: "var foo = \"foo \\000 bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "000" }, type: "Literal" }] },
+        { code: "var foo = \"foo \\377 bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "377" }, type: "Literal" }] },
+        { code: "var foo = \"foo \\378 bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "37" }, type: "Literal" }] },
+        { code: "var foo = \"foo \\37a bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "37" }, type: "Literal" }] },
+        { code: "var foo = \"foo \\381 bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "3" }, type: "Literal" }] },
+        { code: "var foo = \"foo \\3a1 bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "3" }, type: "Literal" }] },
         { code: "var foo = \"foo \\251 bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "251" }, type: "Literal" }] },
-        { code: "var foo = \"\\751\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "75" }, type: "Literal" }] },
+        { code: "var foo = \"foo \\258 bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "25" }, type: "Literal" }] },
+        { code: "var foo = \"foo \\25a bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "25" }, type: "Literal" }] },
         { code: "var foo = \"\\3s51\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "3" }, type: "Literal" }] },
+        { code: "var foo = \"\\77\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "77" }, type: "Literal" }] },
+        { code: "var foo = \"\\78\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "7" }, type: "Literal" }] },
+        { code: "var foo = \"\\5a\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "5" }, type: "Literal" }] },
+        { code: "var foo = \"\\751\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "75" }, type: "Literal" }] },
+        { code: "var foo = \"foo \\400 bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "40" }, type: "Literal" }] },
+
+        { code: "var foo = \"\\t\\1\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
         { code: "var foo = \"\\\\\\751\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "75" }, type: "Literal" }] },
+
         { code: "'\\0\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
         { code: "'\\0 \\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
         { code: "'\\0\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
         { code: "'\\0 \\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
-        { code: "'\\08\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
-        { code: "'\\08\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'\\0a\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "'\\0a\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'\\0\\08'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "0" }, type: "Literal" }] },
+
+        { code: "'\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "'\\2'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "2" }, type: "Literal" }] },
+        { code: "'\\7'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "7" }, type: "Literal" }] },
+        { code: "'\\00'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "00" }, type: "Literal" }] },
+        { code: "'\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'\\02'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "02" }, type: "Literal" }] },
+        { code: "'\\07'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "07" }, type: "Literal" }] },
+        { code: "'\\08'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "0" }, type: "Literal" }] },
+        { code: "'\\09'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "0" }, type: "Literal" }] },
+        { code: "'\\10'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "10" }, type: "Literal" }] },
+        { code: "'\\12'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "12" }, type: "Literal" }] },
+        { code: "' \\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "'\\1 '", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "'a\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "'\\1a'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "'a\\1a'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "' \\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'\\01 '", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'a\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'\\01a'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'a\\01a'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'a\\08a'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "0" }, type: "Literal" }] },
+        { code: "'\\n\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "'\\n\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'\\n\\08'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "0" }, type: "Literal" }] },
+        { code: "'\\\\\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "'\\\\\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'\\\\\\08'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "0" }, type: "Literal" }] },
+
+        // Multiline string
+        { code: "'\\\n\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
 
         // Only the first one is reported
         { code: "'\\01\\02'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
         { code: "'\\02\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "02" }, type: "Literal" }] },
         { code: "'\\01\\2'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
-        { code: "'\\2\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "2" }, type: "Literal" }] }
+        { code: "'\\2\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "2" }, type: "Literal" }] },
+        { code: "'\\08\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "0" }, type: "Literal" }] },
+        { code: "'foo \\1 bar \\2'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] }
     ]
 });
diff --git a/tests/lib/rules/spaced-comment.js b/tests/lib/rules/spaced-comment.js
index fd6b2e510..ee28203d1 100644
--- a/tests/lib/rules/spaced-comment.js
+++ b/tests/lib/rules/spaced-comment.js
@@ -304,6 +304,44 @@ ruleTester.run("spaced-comment", rule, {
         {
             code: "/***\u2028*/",
             options: ["always", { exceptions: ["*"] }]
+        },
+
+        // ignore marker-only comments, https://github.com/eslint/eslint/issues/12036
+        {
+            code: "//#endregion",
+            options: ["always", { line: { markers: ["#endregion"] } }]
+        },
+        {
+            code: "/*foo*/",
+            options: ["always", { block: { markers: ["foo"] } }]
+        },
+        {
+            code: "/*foo*/",
+            options: ["always", { block: { markers: ["foo"], balanced: true } }]
+        },
+        {
+            code: "/*foo*/ /*bar*/",
+            options: ["always", { markers: ["foo", "bar"] }]
+        },
+        {
+            code: "//foo\n//bar",
+            options: ["always", { markers: ["foo", "bar"] }]
+        },
+        {
+            code: "/* foo */",
+            options: ["never", { markers: [" foo "] }]
+        },
+        {
+            code: "// foo ",
+            options: ["never", { markers: [" foo "] }]
+        },
+        {
+            code: "//*", // "*" is a marker by default
+            options: ["always"]
+        },
+        {
+            code: "/***/", // "*" is a marker by default
+            options: ["always"]
         }
     ],
 
@@ -586,6 +624,65 @@ ruleTester.run("spaced-comment", rule, {
             output: null,
             options: ["never"],
             errors: 1
+        },
+
+        // not a marker-only comment, regression tests for https://github.com/eslint/eslint/issues/12036
+        {
+            code: "//#endregionfoo",
+            output: "//#endregion foo",
+            options: ["always", { line: { markers: ["#endregion"] } }],
+            errors: [{
+                message: "Expected space or tab after '//#endregion' in comment.",
+                type: "Line"
+            }]
+        },
+        {
+            code: "/*#endregion*/",
+            output: "/* #endregion*/", // not an allowed marker for block comments
+            options: ["always", { line: { markers: ["#endregion"] } }],
+            errors: [{
+                message: "Expected space or tab after '/*' in comment.",
+                type: "Block"
+            }]
+        },
+        {
+            code: "/****/",
+            output: "/** **/",
+            options: ["always"],
+            errors: [{
+                message: "Expected space or tab after '/**' in comment.",
+                type: "Block"
+            }]
+        },
+        {
+            code: "/****/",
+            output: "/** * */",
+            options: ["always", { block: { balanced: true } }],
+            errors: [
+                {
+                    message: "Expected space or tab after '/**' in comment.",
+                    type: "Block"
+                },
+                {
+                    message: "Expected space or tab before '*/' in comment.",
+                    type: "Block"
+                }
+            ]
+        },
+        {
+            code: "/* foo */",
+            output: "/*foo*/",
+            options: ["never", { block: { markers: ["foo"], balanced: true } }], // not " foo "
+            errors: [
+                {
+                    message: "Unexpected space or tab after '/*' in comment.",
+                    type: "Block"
+                },
+                {
+                    message: "Unexpected space or tab before '*/' in comment.",
+                    type: "Block"
+                }
+            ]
         }
     ]