.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / object-curly-newline.js
diff --git a/.config/coc/extensions/node_modules/coc-prettier/node_modules/eslint/lib/rules/object-curly-newline.js b/.config/coc/extensions/node_modules/coc-prettier/node_modules/eslint/lib/rules/object-curly-newline.js
new file mode 100644 (file)
index 0000000..9b64a1b
--- /dev/null
@@ -0,0 +1,306 @@
+/**
+ * @fileoverview Rule to require or disallow line breaks inside braces.
+ * @author Toru Nagashima
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const astUtils = require("./utils/ast-utils");
+const lodash = require("lodash");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+// Schema objects.
+const OPTION_VALUE = {
+    oneOf: [
+        {
+            enum: ["always", "never"]
+        },
+        {
+            type: "object",
+            properties: {
+                multiline: {
+                    type: "boolean"
+                },
+                minProperties: {
+                    type: "integer",
+                    minimum: 0
+                },
+                consistent: {
+                    type: "boolean"
+                }
+            },
+            additionalProperties: false,
+            minProperties: 1
+        }
+    ]
+};
+
+/**
+ * Normalizes a given option value.
+ * @param {string|Object|undefined} value An option value to parse.
+ * @returns {{multiline: boolean, minProperties: number, consistent: boolean}} Normalized option object.
+ */
+function normalizeOptionValue(value) {
+    let multiline = false;
+    let minProperties = Number.POSITIVE_INFINITY;
+    let consistent = false;
+
+    if (value) {
+        if (value === "always") {
+            minProperties = 0;
+        } else if (value === "never") {
+            minProperties = Number.POSITIVE_INFINITY;
+        } else {
+            multiline = Boolean(value.multiline);
+            minProperties = value.minProperties || Number.POSITIVE_INFINITY;
+            consistent = Boolean(value.consistent);
+        }
+    } else {
+        consistent = true;
+    }
+
+    return { multiline, minProperties, consistent };
+}
+
+/**
+ * Normalizes a given option value.
+ * @param {string|Object|undefined} options An option value to parse.
+ * @returns {{
+ *   ObjectExpression: {multiline: boolean, minProperties: number, consistent: boolean},
+ *   ObjectPattern: {multiline: boolean, minProperties: number, consistent: boolean},
+ *   ImportDeclaration: {multiline: boolean, minProperties: number, consistent: boolean},
+ *   ExportNamedDeclaration : {multiline: boolean, minProperties: number, consistent: boolean}
+ * }} Normalized option object.
+ */
+function normalizeOptions(options) {
+    const isNodeSpecificOption = lodash.overSome([lodash.isPlainObject, lodash.isString]);
+
+    if (lodash.isPlainObject(options) && Object.values(options).some(isNodeSpecificOption)) {
+        return {
+            ObjectExpression: normalizeOptionValue(options.ObjectExpression),
+            ObjectPattern: normalizeOptionValue(options.ObjectPattern),
+            ImportDeclaration: normalizeOptionValue(options.ImportDeclaration),
+            ExportNamedDeclaration: normalizeOptionValue(options.ExportDeclaration)
+        };
+    }
+
+    const value = normalizeOptionValue(options);
+
+    return { ObjectExpression: value, ObjectPattern: value, ImportDeclaration: value, ExportNamedDeclaration: value };
+}
+
+/**
+ * Determines if ObjectExpression, ObjectPattern, ImportDeclaration or ExportNamedDeclaration
+ * node needs to be checked for missing line breaks
+ * @param {ASTNode} node Node under inspection
+ * @param {Object} options option specific to node type
+ * @param {Token} first First object property
+ * @param {Token} last Last object property
+ * @returns {boolean} `true` if node needs to be checked for missing line breaks
+ */
+function areLineBreaksRequired(node, options, first, last) {
+    let objectProperties;
+
+    if (node.type === "ObjectExpression" || node.type === "ObjectPattern") {
+        objectProperties = node.properties;
+    } else {
+
+        // is ImportDeclaration or ExportNamedDeclaration
+        objectProperties = node.specifiers
+            .filter(s => s.type === "ImportSpecifier" || s.type === "ExportSpecifier");
+    }
+
+    return objectProperties.length >= options.minProperties ||
+        (
+            options.multiline &&
+            objectProperties.length > 0 &&
+            first.loc.start.line !== last.loc.end.line
+        );
+}
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        type: "layout",
+
+        docs: {
+            description: "enforce consistent line breaks after opening and before closing braces",
+            category: "Stylistic Issues",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/object-curly-newline"
+        },
+
+        fixable: "whitespace",
+
+        schema: [
+            {
+                oneOf: [
+                    OPTION_VALUE,
+                    {
+                        type: "object",
+                        properties: {
+                            ObjectExpression: OPTION_VALUE,
+                            ObjectPattern: OPTION_VALUE,
+                            ImportDeclaration: OPTION_VALUE,
+                            ExportDeclaration: OPTION_VALUE
+                        },
+                        additionalProperties: false,
+                        minProperties: 1
+                    }
+                ]
+            }
+        ],
+
+        messages: {
+            unexpectedLinebreakBeforeClosingBrace: "Unexpected line break before this closing brace.",
+            unexpectedLinebreakAfterOpeningBrace: "Unexpected line break after this opening brace.",
+            expectedLinebreakBeforeClosingBrace: "Expected a line break before this closing brace.",
+            expectedLinebreakAfterOpeningBrace: "Expected a line break after this opening brace."
+        }
+    },
+
+    create(context) {
+        const sourceCode = context.getSourceCode();
+        const normalizedOptions = normalizeOptions(context.options[0]);
+
+        /**
+         * Reports a given node if it violated this rule.
+         * @param {ASTNode} node A node to check. This is an ObjectExpression, ObjectPattern, ImportDeclaration or ExportNamedDeclaration node.
+         * @returns {void}
+         */
+        function check(node) {
+            const options = normalizedOptions[node.type];
+
+            if (
+                (node.type === "ImportDeclaration" &&
+                    !node.specifiers.some(specifier => specifier.type === "ImportSpecifier")) ||
+                (node.type === "ExportNamedDeclaration" &&
+                    !node.specifiers.some(specifier => specifier.type === "ExportSpecifier"))
+            ) {
+                return;
+            }
+
+            const openBrace = sourceCode.getFirstToken(node, token => token.value === "{");
+
+            let closeBrace;
+
+            if (node.typeAnnotation) {
+                closeBrace = sourceCode.getTokenBefore(node.typeAnnotation);
+            } else {
+                closeBrace = sourceCode.getLastToken(node, token => token.value === "}");
+            }
+
+            let first = sourceCode.getTokenAfter(openBrace, { includeComments: true });
+            let last = sourceCode.getTokenBefore(closeBrace, { includeComments: true });
+
+            const needsLineBreaks = areLineBreaksRequired(node, options, first, last);
+
+            const hasCommentsFirstToken = astUtils.isCommentToken(first);
+            const hasCommentsLastToken = astUtils.isCommentToken(last);
+
+            /*
+             * Use tokens or comments to check multiline or not.
+             * But use only tokens to check whether line breaks are needed.
+             * This allows:
+             *     var obj = { // eslint-disable-line foo
+             *         a: 1
+             *     }
+             */
+            first = sourceCode.getTokenAfter(openBrace);
+            last = sourceCode.getTokenBefore(closeBrace);
+
+            if (needsLineBreaks) {
+                if (astUtils.isTokenOnSameLine(openBrace, first)) {
+                    context.report({
+                        messageId: "expectedLinebreakAfterOpeningBrace",
+                        node,
+                        loc: openBrace.loc,
+                        fix(fixer) {
+                            if (hasCommentsFirstToken) {
+                                return null;
+                            }
+
+                            return fixer.insertTextAfter(openBrace, "\n");
+                        }
+                    });
+                }
+                if (astUtils.isTokenOnSameLine(last, closeBrace)) {
+                    context.report({
+                        messageId: "expectedLinebreakBeforeClosingBrace",
+                        node,
+                        loc: closeBrace.loc,
+                        fix(fixer) {
+                            if (hasCommentsLastToken) {
+                                return null;
+                            }
+
+                            return fixer.insertTextBefore(closeBrace, "\n");
+                        }
+                    });
+                }
+            } else {
+                const consistent = options.consistent;
+                const hasLineBreakBetweenOpenBraceAndFirst = !astUtils.isTokenOnSameLine(openBrace, first);
+                const hasLineBreakBetweenCloseBraceAndLast = !astUtils.isTokenOnSameLine(last, closeBrace);
+
+                if (
+                    (!consistent && hasLineBreakBetweenOpenBraceAndFirst) ||
+                    (consistent && hasLineBreakBetweenOpenBraceAndFirst && !hasLineBreakBetweenCloseBraceAndLast)
+                ) {
+                    context.report({
+                        messageId: "unexpectedLinebreakAfterOpeningBrace",
+                        node,
+                        loc: openBrace.loc,
+                        fix(fixer) {
+                            if (hasCommentsFirstToken) {
+                                return null;
+                            }
+
+                            return fixer.removeRange([
+                                openBrace.range[1],
+                                first.range[0]
+                            ]);
+                        }
+                    });
+                }
+                if (
+                    (!consistent && hasLineBreakBetweenCloseBraceAndLast) ||
+                    (consistent && !hasLineBreakBetweenOpenBraceAndFirst && hasLineBreakBetweenCloseBraceAndLast)
+                ) {
+                    context.report({
+                        messageId: "unexpectedLinebreakBeforeClosingBrace",
+                        node,
+                        loc: closeBrace.loc,
+                        fix(fixer) {
+                            if (hasCommentsLastToken) {
+                                return null;
+                            }
+
+                            return fixer.removeRange([
+                                last.range[1],
+                                closeBrace.range[0]
+                            ]);
+                        }
+                    });
+                }
+            }
+        }
+
+        return {
+            ObjectExpression: check,
+            ObjectPattern: check,
+            ImportDeclaration: check,
+            ExportNamedDeclaration: check
+        };
+    }
+};