Git Product home page Git Product logo

eslint-plugin-align-assignments's Introduction

Hola!

  • Currently working for Community Phone, and not looking for a job.

eslint-plugin-align-assignments's People

Contributors

elmbank avatar lucasefe avatar pascalpp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

eslint-plugin-align-assignments's Issues

PR, wrote you some code for better assignment.

Feel free to modify it as required.

const hasRequire=       /require\(/u;
const spaceMatcher=     /(?<n2>\s*)(?<n1>(?:\+|-|\*|\/|%|&|\^|\||<<|>>|\*\*|>>>)?=)/u;
const assignmentTokens= new Set ([
  `>>>=`,
  `<<=`,
  `>>=`,
  `**=`,
  `&&=`,
  `||=`,
  `??=`,
  `+=`,
  `-=`,
  `*=`,
  `/=`,
  `%=`,
  `&=`,
  `^=`,
  `|=`,
  `=`,
]);

module.exports= {
  meta: {
    fixable: `code`,
  },

  create: function (context) {
    const {
      options,
    } = context;
    const requiresOnly= Boolean (options) && options.length > 0 && options[0].requiresOnly;
    const sourceCode=   context.getSourceCode ();
    const groups=       [];
    let previousNode;
    return {
      "VariableDeclaration": function (node) {
        const source= sourceCode.getText (node);
        if (Boolean (requiresOnly) && ! hasRequire.test (source)) {
          return;
        }
        addNode (node, node);
      },
      "Program:exit":        checkAll,
      "ExpressionStatement": function (node) {
        const hasAssignmentExpression= Object.is (`AssignmentExpression`, node.expression.type);
        if (! hasAssignmentExpression) {
          return;
        }
        addNode (node, node.expression);
      },
    };
    function checkAll () {
      groups.forEach (check);
    }
    function isAssignmentExpression (node) {
      return Object.is (`AssignmentExpression`, node.type);
    }
    function addNode (groupNode, node) {
      if (shouldStartNewGroup (groupNode)) {
        groups.push ([
          node,
        ]);
      }
      else {
        getLast (groups).push (node);
      }
      previousNode= groupNode;
    }
    function shouldStartNewGroup (node) {
      // first line of all
      if (! previousNode) {
        return true;
      }
      // switching parent nodes
      if (! Object.is (previousNode.parent, node.parent)) {
        return true;
      }
      // If previous node was a for and included the declarations, new group
      if (Object.is (`ForStatement`, previousNode.parent.type) && previousNode.declarations) {
        return true;
      }
      // previous line was blank.
      const lineOfNode= sourceCode.getFirstToken (node).loc.start.line;
      const lineOfPrev= sourceCode.getLastToken (previousNode).loc.start.line;

      return ! Object.is (1, lineOfNode - lineOfPrev);
    }
    function check (group) {
      const maxPos= maxPosition (group);
      if (! areAligned (maxPos, group)) {
        context.report ({
          message: `This group of assignments is not aligned.`,
          loc:     {
            start: group[0].loc.start,
            end:   getLast (group).loc.end,
          },
          fix: fixer=>{
            const fixings= group.map (node=>{
              const tokens=          sourceCode.getTokens (node);
              const firstToken=      tokens[0];
              const assignmentToken= tokens.find (token=>assignmentTokens.has (token.value));
              const line=            sourceCode.getText (node);
              const lineIsAligned=   ! Object.is (` `, line.charAt (maxPos+1)) && Object.is (` `, line.charAt (maxPos));
              if (lineIsAligned || ! assignmentToken || isMultiline (firstToken, assignmentToken)) {
                return fixer.replaceText (node, line);
              }
              // source line may include spaces, we need to accomodate for that.
              const spacePrefix=    firstToken.loc.start.column;
              const startDelimiter= assignmentToken.loc.start.column - spacePrefix;
              const endDelimiter=   assignmentToken.loc.end.column - spacePrefix;
              const start=          line.slice (0, startDelimiter).replace (/\s+$/um, ``);
              const ending=         line.slice (endDelimiter).replace (/^\s+/um, ``);
              const spacesRequired= maxPos - start.length - assignmentToken.value.length + 1;
              const spaces=         ` `.repeat (spacesRequired);
              const fixedText=      `${start}${assignmentToken.value}${spaces}${ending}`;

              return fixer.replaceText (node, fixedText);
            });

            return fixings.filter (Boolean);
          },
        });
      }
    }
    function isMultiline (firstToken, assignmentToken) {
      return ! Object.is (firstToken.loc.start.line, assignmentToken.loc.start.line);
    }
    function findAssigment (node) {
      const prefix=   getPrefix (node);
      const source=   sourceCode.getText (node);
      const match=    source.slice (prefix).match (spaceMatcher);
      const position= match ?
        match.index + prefix + match[2].length :
        null;

      return position;
    }
    function getPrefix (node) {
      const nodeBefore= isAssignmentExpression (node) ?
        node.left:
        node.declarations.find (dcl=>Object.is (`VariableDeclarator`, dcl.type)).id;
      const prefix=     nodeBefore.loc.end.column - nodeBefore.loc.start.column;

      return prefix;
    }
    function areAligned (maxPos, nodes) {
      return nodes
        .filter (assignmentOnFirstLine)
        .map (node=>sourceCode.getText (node))
        .every (source=>{
          return ! Object.is (` `, source.charAt (maxPos+1)) &&
            Object.is (` `, source.charAt (maxPos+0));
        });
    }
    function maxPosition (nodes) {
      return nodes
        .filter (assignmentOnFirstLine)
        .map (findAssigment)
        .reduce ((previous, current)=>{
          return Math.max (previous, current);
        }, 0);
    }
    function assignmentOnFirstLine (node) {
      if (isAssignmentExpression (node)) {
        const onFirstLine= Object.is (node.right.loc.start.line, node.left.loc.start.line);

        return onFirstLine;
      }
      const source= sourceCode.getText (node);
      const lines=  source.split (`\n`);

      return lines[0].includes (`=`);
    }
    function getLast (ary) {
      return ary.at (- 1);
    }
  },
};

Cheers.

Support all assignment operators

Operators like = += -= *= /= %= <<= >>= >>>= &= ^= \|= should be valid assignment operators, and the plugin should be able to align them properly.

Suggestion of what would be valid.

a   *= 3;
b  >>= 3;
f >>>= 3;

Destructuring single-line assignments

First, very many thanks for writing this package. I have been looking for a way to enforce aligned assignment in eslint for over a year.

I am finding that supplying defaults for destructuring single-line assignments confuses this plugin, for example:

const { foo = [] } = bar;

reports 'This group of assignments is not aligned'. The 'fix' produces:

const { foo            = [] } = bar;

which is not only worse but also does not stop the rule from complaining.

Types are ignored

No detection/alignment of:

type MyType = [number, string, string];
type MyOtherType = [string, number];

Adding the plugin to the plugins section makes eslint stop working

Edit: I also noticed it shows the error "Definition for rule 'align-assignments/align-assignments' was not found." with the plugin enabled.

In .eslintrc.json I have:

	"plugins": [
		***
		"align-assignments",
		***
	],

Which breaks eslint as if there's a syntax or some other error in the configuration file.

When I remove the plugin, eslint works normally:
Code_j9hrdO8Jua

Alignment of object properties after a function

It would seem that the function as an object property somehow resets the indentation level.

Expected look after auto-fix:

var obj = {
    arr           : [ 1, 2, 3 ],
    obj_inner1    : { empty: true },
    long_fun_name : function f() {
        return 42;
    },
    obj_inner2    : { empty: true },
};

Current behavior:

var obj = {
    arr           : [ 1, 2, 3 ],
    obj_inner1    : { empty: true },
    long_fun_name : function f() {
        return 42;
    },
    obj_inner2: { empty: true },
};

If I write the function in one line it's working as expected:

var obj = {
    arr           : [ 1, 2, 3 ],
    obj_inner1    : { empty: true },
    long_fun_name : function f() { return 42; },
    obj_inner2    : { empty: true },
};

These are my rule settings:

  rules: {
      "key-spacing": ["error", {
          "mode": "minimum",
          "align": {
              "beforeColon": true,
              "afterColon": true,
              "on": "colon"
          }
      }],
      // PLUGIN rules
      "align-assignments/align-assignments": [2, { "requiresOnly": false } ],
  },

ESLint version: v5.16.0

Comments should not reset groups (Optional)

Let's say you have:

const hi = 1;
// Something nice about bye
const bye = 2;

This is valid.

Optionally, I could want to treat the whole thing as a group, making this valid instead.

const hi  = 1;
// Something nice about bye
const bye = 2;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.