Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rule proposal: Expiring TODO comments #238

Closed
sindresorhus opened this issue Feb 5, 2019 · 40 comments · Fixed by #302
Closed

Rule proposal: Expiring TODO comments #238

sindresorhus opened this issue Feb 5, 2019 · 40 comments · Fixed by #302
Labels
enhancement 🎁 Rewarded on Issuehunt This issue has been rewarded on Issuehunt help wanted

Comments

@sindresorhus
Copy link
Owner

sindresorhus commented Feb 5, 2019

Issuehunt badges

For example, // TODO [2018-05-01]: Do this thing would be reported from that date and onwards. The date format should be YYYY-MM-DD (ISO 8601).

Would also be nice to support semver, for example, // TODO [>=2]: Do this thing, which would make it report from version 2 and later.


IssueHunt Summary

lubien lubien has been rewarded.

Backers (Total: $100.00)

Submitted pull Requests


Tips


IssueHunt has been backed by the following sponsors. Become a sponsor

@futpib
Copy link
Contributor

futpib commented Feb 5, 2019

Should they be warnings before the date/version and errors after, or not reported before and reported as warnings after?

Is it ok for a random contributor to get a TODO he has no idea about reported, just because he happen to contribute at the time of it's expiry?

@MrHen
Copy link
Contributor

MrHen commented Feb 5, 2019

I really like the "from version 2" variant of this feature because it can give you a way to start progressively cleaning up TODOs. If this option is enabled, should it always warn for TODOs without a date / version?

@sindresorhus
Copy link
Owner Author

Should they be warnings before the date/version and errors after, or not reported before and reported as warnings after?

Silent before and error/warning (depends on what the user sets in their config) after.

Is it ok for a random contributor to get a TODO he has no idea about reported, just because he happen to contribute at the time of it's expiry?

Hmm, good point. We could have an opt-in option to not report in pull requests? Can be detected with https://github.com/watson/ci-info#ciispr

If this option is enabled, should it always warn for TODOs without a date / version?

Yes, it would have to replace the functionality of no-warning-comments as it conflicts.

@sindresorhus
Copy link
Owner Author

Anything else we cool could do with TODO comments other than versions and dates?

@MrHen
Copy link
Contributor

MrHen commented Feb 6, 2019

Anything else we cool could do with TODO comments other than versions and dates?

I've seen specific tools for making sure each TODO has an issue / bug number which is really helpful for making sure TODOs are actually being tracked. It would require an opinion on how to format it. Perhaps, // TODO: #123 - Thing to do here or // TODO (#123) - Thing to do here.

The two common ways I see bug tickets formatted are #123 and ABC-123. Both seem pretty easy to regex which means it would be easy to right a linter for them. Perhaps with a format: 'jira' config on the rule.


In terms of dates, treating the date like a timestamp of when the TODO was added might be more intuitive. If I saw:

// TODO 2018-05-01 - Shouldn't do it like this.

I would probably think, "This TODO was added on 05-01". Six months later when the linter complains that I have a six month old TODO I could either:

  • Fix the TODO
  • Update the timestamp to "approve" the TODO for another six months
  • Increase the expiration date in the lint rule

@zeorin
Copy link

zeorin commented Feb 7, 2019

The other thing one could optionally require in a TODO is an identifier for the author, like a name, username/handle, initials, or email address. I know using the blame/annotate features of your VCS can usually tell you who wrote a line of code, there are situations where that history is lost:

  • File name changes (moves)
  • Refactoring (moving pieces of code around)
  • Reformatting (e.g. after introducing Prettier to a JS codebase).

In all those cases knowing who originally wrote the comment is helpful.

@zeorin
Copy link

zeorin commented Feb 7, 2019

There are also some other commonly-used comments like FIXME and XXX that I've seen around. Should probably include those.

@sindresorhus
Copy link
Owner Author

sindresorhus commented Feb 13, 2019

The two common ways I see bug tickets formatted are #123 and ABC-123. Both seem pretty easy to regex which means it would be easy to right a linter for them. Perhaps with a format: 'jira' config on the rule.

I could see this being useful for companies. Personally, I prefer just keeping my TODOs only in code. Instead having named formats, we could just accept a regex.

I would probably think, "This TODO was added on 05-01". Six months later when the linter complains that I have a six month old TODO I could either:

That's a different use-case than what I proposed though. This limits the duration of a TODO, while mine is for a fixed date. Both are valid, but they serve different purposes.

What if we made the syntax for my proposal // TODO [from: 2018-05-01]: Do this thing. Would that make it clearer?

@sindresorhus
Copy link
Owner Author

The other thing one could optionally require in a TODO is an identifier for the author, like a name, username/handle, initials, or email address.

👍 The common syntax I have seen for this is // TODO(sindresorhus): Lorem ipsum..

@sindresorhus
Copy link
Owner Author

There are also some other commonly-used comments like FIXME and XXX that I've seen around. Should probably include those.

👍 FIXME. For additional ones, we could allow specifying a list of keywords.

@alexzherdev
Copy link
Contributor

Continuing the idea about semver, should be doable to require a version of a dependency? E.g.,

// TODO [react@>=16.8]: refactor to hooks

@sindresorhus
Copy link
Owner Author

@alexzherdev Good idea! That would indeed be very useful.

@futpib
Copy link
Contributor

futpib commented Feb 15, 2019

Also consider TODOs that pop up when a dependency is removed or added (in case you are migrating between substitute packages like lodash/ramda, preact/react etc.)

Not sure which syntax will be best:

// TODO [-lodash]: A workaround for lodash#12345
// TODO [+react]: After switching to react, we will not need this hack

or

// TODO [npm r lodash]: A workaround for lodash#12345
// TODO [npm i react]: After switching to react, we will not need this hack

@sindresorhus
Copy link
Owner Author

[+react] 👍

@futpib
Copy link
Contributor

futpib commented Mar 21, 2019

Conditions based on the engines field from package.json may be handy.

// TODO [engines node>=10]: Use named capture groups

Inspired by this comment #244 (comment)

@sindresorhus
Copy link
Owner Author

@futpib Yes, that would be very useful for me. Add a lot of those comments so I will remember to improve the code in the future.

@IssueHuntBot
Copy link

@IssueHunt has funded $100.00 to this issue.


@futpib
Copy link
Contributor

futpib commented Apr 11, 2019

I wonder if dates should be treated as UTC rather than local to prevent a possibility of an error reported in CI but not locally (or similarly for collaborators in different timezones). Or maybe we should require timezone explicitly in the date format.

@sindresorhus
Copy link
Owner Author

Yes, I think we should treat them as UTC.

@guillaumeklaus
Copy link

Would love to work on this rule proposal if it is not already assigned! :)

@issuehunt-oss issuehunt-oss bot added the 💵 Funded on Issuehunt This issue has been funded on Issuehunt label May 10, 2019
lubien added a commit to lubien/eslint-plugin-unicorn that referenced this issue May 30, 2019
Fixes sindresorhus#238

* Due date check.
* Own package version check.
* Dependency package version check.
* Dependency inclusion checks.
lubien added a commit to lubien/eslint-plugin-unicorn that referenced this issue May 30, 2019
Fixes sindresorhus#238

* Due date check.
* Own package version check.
* Dependency package version check.
* Dependency inclusion checks.
@sindresorhus
Copy link
Owner Author

@lubien Any thoughts on #238 (comment) ?

@lubien
Copy link
Contributor

lubien commented May 30, 2019

@lubien Any thoughts on #238 (comment) ?

So far I enjoyed implementing this rule (never had experience with making my own eslint rule before) so it was a nice opportunity specially since it was by far the most out of the box eslint rule I've heard about and sure picked my interest at first sight.

Some points that still puzzle me at some points are:

  1. Wouldn't checking for CI during PRS be bad since once the branch is merged the master would immediately break? I feel like it would be bad for maintainers but I also won't like to ask any unfortunate contributor who happened to make a PR on a TODO expire date do whatever it was.
  2. engines check sure is a good way to go but I'd love to have some examples since altho I met it I've never used it before.
  3. I have to look for how to support different TODO verbs (currently only available TODO and FIXME as pointed before)

lubien added a commit to lubien/eslint-plugin-unicorn that referenced this issue May 30, 2019
Fixes sindresorhus#238

* Due date check.
* Own package version check.
* Dependency package version check.
* Dependency inclusion checks.
@lubien
Copy link
Contributor

lubien commented May 30, 2019

  1. Sure:

Oh. I'll add to my TODO list. No pun intended.

@lubien
Copy link
Contributor

lubien commented May 30, 2019

Yup, pretty much finished it.

@zeorin
Copy link

zeorin commented Jun 8, 2019

👍 FIXME. For additional ones, we could allow specifying a list of keywords.

The built-in no-warning-comments rule defaults to ['todo', 'fixme', 'xxx'].

@lubien
Copy link
Contributor

lubien commented Jun 8, 2019

@zeorin got your back:

https://github.com/sindresorhus/eslint-plugin-unicorn/pull/302/files#diff-0765ede6250731541d69a380accdc19cR20

lubien added a commit to lubien/eslint-plugin-unicorn that referenced this issue Jun 25, 2019
Fixes sindresorhus#238

* Due date check.
* Own package version check.
* Dependency package version check.
* Dependency inclusion checks.
@brettz9
Copy link
Contributor

brettz9 commented Jun 29, 2019

Sorry to join the party a bit late, but I have the following suggested improvements and customizations. Some could be implemented over time, but I think it is helpful to have in mind some of what I see as some very cool additional possibilities here...

Some proposed to-dos for the to-dos

  1. Rename the rule to just todos, as the following adds more generic uses.
  2. Option to include the to-do in or as the message.
  3. Support to-do scopes and priorities, whether as numbers or string enums, e.g., {1: 'High', 2: 'Medium', 3: 'Low'}
  4. Allow rule options that can be used as queries (See next main item on how this could be useful):
    1. comma-separated or hyphen-range of numbers or strings enums for priority and scope, e.g., High,Low, 2-5, High-Low, testing,optimization,refactoring
    2. add to or refactor date range, semver, and package queries such that the rule will accept an option indicating a specific acceptable range, e.g., to find all to-dos related to XYZ package, which expire in the future, etc. For example, "unicorn/todos": ["warn", {dates: "now to 2021", packages: "somePkg>={current}; +anotherPackage; -yetAnotherPackage", priorities: "3-5", priorityMap: {3: "Next release", 4: "Future release", 5: "If we get to it"}, scopes: "testing,optimization"}]. Also be able to search for to-dos with or without expiries. And rather than naming it as "expiry", thereby forcing the dates used to be expiries, allow it to be generic in case some projects wish to say insist on comments timestamped when they were added.
  5. Draw attention in the docs to the fact that some queries (e.g., date ranges), even if not useful as regular rules, can be useful through using the eslint command line to mine information out of one's to-dos, (with --rule including the rule's (range) options and --no-eslintrc, and possibly --fix, to get a listing, and possibly piping output to a file). Or, even better, a binary could be shipped to simplify this, e.g., todo --date "2008 to now", todo --priority "1-3" --date "never" --output "TO-DOS.md" or todo --scope "optimization" --date "any" --remove.
  6. While giving a default, give a rule option to make the to-do format entirely customizable, possibly via a regular expression with substitutions format: "// (todo|fixme) \\({scope}\\)( [{expiry}])?( \-{priority})?: "
  7. Add custom formatters which can be used (with --formatter) to output to-dos to a file as Markdown (and possibly as plain text or JavaScript comments), ideally with options to sort by priority and/or scope and/or expiry, optionally under separate headings/subheadings.
  8. Also parse jsdoc @todo (so that asterisks across multiple lines can be stripped)

Edit: One other item: intended version number release for querying (useful so that to-dos can be built in a hierarchy (even in one's Markdown) by functionality or concept rather than priority)

@lubien
Copy link
Contributor

lubien commented Jun 29, 2019

@brettz9

1: Maybe there should be a rename but just todos doesn't feel like making justice to the whole cake (assuming your proposal is implemented), at least to me.

2: Could you elaborate?

3 and 4(i): Great but how this relate to the failing/warning aspect of eslint? Legit question.

4(ii), 5 and 7: Would be a lot useful to have this kind of report especially when you're hunting todos! I feel this binary is pretty doable for sure but before I try some shady dealing do you happen to know any case like this? (Specially for ESLint to get some implementation ideas but also in another languages, perhaps).

6: Good point.

8: I forgot that one. Got some examples that relate to our discussion that I could learn from?

My ideals apart.

@sindresorhus do you feel we should go for this approach or for this kind of rule we should make the scope simple as is?

@lubien
Copy link
Contributor

lubien commented Jun 29, 2019

Sorry, I squeezed in an item #2 before your comments... (Plan to respond shortly.)

Updated and added a question.

@MrHen
Copy link
Contributor

MrHen commented Jun 29, 2019

Support to-do scopes and priorities. [...]

Todos in comments are not a particularly great way to organize things -- if someone needs things like priorities than they should move the todos to an issue tracker and reference the issue number in the todo.

Allow rule options that can be used as queries. [...]

All of the possible intent you discuss should be "encoded" in the expiration syntax by the person writing the todo. The warning check should stay simple enough to provide an unambiguous warning.

Taking a big step back: The point of a lint rule is to enforce code style and standards. Todos are generally bad for code health. The premise of this rule is to allow todos for a short period of time with a trigger for when they should be removed. Expanding beyond that purpose sounds too complicated and too much of an opinion farm around what configurations should or should not exist.

Draw attention in the docs to the fact that some queries [...] can be useful through using the eslint command line to mine information out of one's to-dos.

This is what issue trackers are for. I would heavily discourage trying to maintain this kind of information in the code base itself and definitely not via a lint rule.

Or, even better, a binary could be shipped to simplify this[...]

A todo tool that just managed todos on their own is a pretty good idea. It is far, far beyond the scope of a lint rule.

@brettz9
Copy link
Contributor

brettz9 commented Jun 29, 2019

1: Up to y'all, but to me, some of the most powerful packages are short and sweet in their names, implying that they are meant to "do it all" more or less.

2: If the rule def. were "unicorn/todos": ["warn", {include: ["error", "message"]}], the actual to-do contents would show up along with the error, e.g., if the to-do were // todo: fix this mess, the error message for eslint would be something like "Unexpected to-do: fix this mess". A template might be even better: "unicorn/todos": ["warn", {include: "{error}: {todo}"}], allowing one to get rid of "Unexpected to-do" and just show the to-do text (by just using {include: "{todo}"}). Besides the fact that this option would allow the custom formatters to work (as they'd need to get access to the actual to-do message to be able to extract it), sometimes even when linting code, it can be useful to see what the to-do is within one's IDE linting panel among the other coding issues (e.g., it would show "fix this mess" in the linter panel, so we'd know which to-do was failing).

3 and 4(i): The scopes and priorities would relate to failing/warning because the following rule would only cause priorities "High" (or "1") to fail (and be optionally fixable): "unicorn/todos": ["warn", {priorities: "High", priorityMap: {1: 'High', 2: 'Medium', 3: 'Low'}}] This would probably be most useful for querying/formatters, so one could get a listing of the priorities/scopes of interest, but it could even be of interest to regular linting, e.g., if one wanted to insist that "High" priority to-dos were always failing because they shouldn't end up in a commit until resolved, while lower priority to-dos could be safely ignored for the time-being. The priorityMap would be optional but would allow the target to be detected as an alias within the comment (e.g., // Todo (High) or // Todo (1)), and also to be used within the range, e.g., priorities: "High-Low".

Scopes would have similar uses, both to querying/formatters and even during regular code linting, e.g., one might wish to ignore // todo (refactor): while reporting // todo (bug): .

4(ii), 5 and 7: Which aspect of 4ii were you not clear on? Re: no. 5, the binary could perhaps just be a wrapper around the eslint command line (documented at https://eslint.org/docs/user-guide/command-line-interface ), e.g., using Node's exec or spawn to run the eslint command perhaps. Or it could directly use the Node API, e.g., with https://eslint.org/docs/developer-guide/nodejs-api#cliengine . You might find some command-line argument parsing tools helpful like https://www.npmjs.com/package/command-line-args . Re: no. 7, see https://eslint.org/docs/developer-guide/working-with-custom-formatters (I'm not clear if it receives the rule options on the data object, but if it does, you could use that: https://eslint.org/docs/developer-guide/working-with-custom-formatters#the-data-argument ; if not, perhaps your binary wrapper could dynamically create a custom formatter based on the supplied arguments). Let me know if you need more clarification or are looking for something else.

8: @todo would probably be structured just the same as todo (though jsdoc would always expect a space after @todo so that should be enforced). The reason it couldn't just be added to the regular expression of #6 is that a regular expression wouldn't work well with:

/**

* @todo  Some long,

*  multiline to-do

*  comment.

*/

One could use https://github.com/yavorskiy/comment-parser/ to get the todo collapsed into "Some long, multiline to-do comment".

@lubien
Copy link
Contributor

lubien commented Jun 29, 2019

@brettz9

2: Sounds great.

3 and 4(i): I'm inclined to say now I see, as @MrHen said, it's probably better go for a issue tracker.

4(ii), 5 and 7: It was clear and I am also used to NodeJS CLIs, thanks. I just wanted to know if you had seen some sort of integration directly with ESLint like this scenario or maybe in another programming language (because I feel like there must be something like this).

8: I see. Worth checking.

@brettz9
Copy link
Contributor

brettz9 commented Jun 29, 2019

Support to-do scopes and priorities. [...]

Todos in comments are not a particularly great way to organize things -- if someone needs things like priorities than they should move the todos to an issue tracker and reference the issue number in the todo.

I disagree. I use them all of the time and don't find it redundant with trackers or conducive to disorganization, and would use them even more if I didn't have to find-in-files.

I use issue trackers for items of public interest, or where a lot more explanation is justified or for which I feel the time is justified to add them there. I keep track of other to-dos, particularly refactoring ones, inline along with the context. There's always a trade-off between whether to store the to-dos inline or in the tracker (unless the tracker software could maintain links and direct editing in context). There's also a spectrum of how much detail one would wish to put inline and what would necessitate a tracker issue. But that doesn't mean one must be dogmatic and refuse to put anything inline around the context where it needs to get implemented and where it is likely to be discovered by someone digging into the code. And if one can query one's inline rules and get them into a formatted report, it can include some of the best of both approaches--having context, but seeing a comprehensive list.

Allow rule options that can be used as queries. [...]

All of the possible intent you discuss should be "encoded" in the expiration syntax by the person writing the todo. The warning check should stay simple enough to provide an unambiguous warning.

I also disagree here. Sometimes I am interested in my low priority to-dos, and sometimes in my high priority ones. Or those of a particular scope. People who want a simple warning without the to-do text appended or replacing the message can do so.

Taking a big step back: The point of a lint rule is to enforce code style and standards.

The purpose of a lint rule is whatever one finds useful for them. I find it useful to see and query the messages of my to-dos alongside coding errors and styling problems because, as you say, to-dos can be bad for code health, but it would help to have control over which types were reported, just as one has control over whether to report/fix stylistic suggestions or errors, since one does not have all the time in the world to improve everything that needs improving all at one time.

Todos are generally bad for code health.

To-dos indeed can be bad for code health, and as mentioned, it would help if the developer had control over the types reported. But to-dos can also be good for code health, as a reminder to refactor later when one has more time is better than having no reminder or putting it in a tracker where it might get forgotten being outside of the original context, or it might deter the developer from fixing because after looking at the tracker, they have to dig through the code to find where that code in need of refactoring is. Whereas if they run a query, they can jump to that line quickly without need of duplicating links and line numbers within an issue tracker.

Expanding beyond that purpose sounds too complicated and too much of an opinion farm around what configurations should or should not exist.

Given the customization options mentioned, a project can determine whatever configuraiton it wishes to enforce. Defaults can be provided so there is no need for the work of customization unless desired.

Draw attention in the docs to the fact that some queries [...] can be useful through using the eslint command line to mine information out of one's to-dos.

This is what issue trackers are for. I would heavily discourage trying to maintain this kind of information in the code base itself and definitely not via a lint rule.

Or, even better, a binary could be shipped to simplify this[...]

A todo tool that just managed todos on their own is a pretty good idea. It is far, far beyond the scope of a lint rule.

I disagree that it has no place in a linting rule, as some to-dos are helpful to be discoverable during the linting process. Whether it has a place in this project is not my call.

@MrHen
Copy link
Contributor

MrHen commented Jun 29, 2019

I disagree that it has no place in a linting rule, as some to-dos are helpful to be discoverable during the linting process. Whether it has a place in this project is not my call.

I think the current scope is suitable for the first pass on this rule. My recommendation is to focus on the current PR by @lubien. That work would be necessary to support what you are proposing anyway. Once that PR is in, this issue should be closed.

If you want to continue championing these ideas, let's split them off into a different issue so we can discuss them in more detail without conflating them with the scope in @lubien's PR.

@brettz9
Copy link
Contributor

brettz9 commented Jun 30, 2019

Do people consider it acceptable for items 2, 6, 8 to be in scope though?

i.e.

  1. Option to include the to-do in or as the message, ideally as a template, e.g., {message: "{lintError}: {todoText}"}) so people could choose whether to include the error and/or the message, defaulting perhaps to just the lint error.
  2. While giving a default, give a rule option to make the to-do format entirely customizable, as via a regular expression with substitutions format: "// (todo|fixme) ( \\[{{expiry}}\\])?: "
  3. Also parse jsdoc @todo (so that asterisks across multiple lines can be stripped)

no. 8 would imo be a "nice to have" and not too far out of scope for this PR, I think, but 2 and 6 I feel to be very important.

@MrHen
Copy link
Contributor

MrHen commented Jun 30, 2019

Option to include the to-do in or as the message, ideally as a template.

Out-of-scope, as I'm not yet convinced this is a good idea.

While giving a default, give a rule option to make the to-do format entirely customizable.

Out-of-scope, as I'm not yet convinced this is a good idea.

Also parse jsdoc.

I think we can at least split jsdoc support off to a separate PR. The PR is big enough as it is and starting to stabilize. I don't think it should be a requirement for the existing bounty (but the final call on that is for @sindresorhus.)

@sindresorhus
Copy link
Owner Author

  1. This is exactly why the name is not short and sweet. The rule is definitely not meant to do it all.
  2. The TODO comment contents will be included in the error by default: Add expiring-todo-comments rule #302 (comment) Not really interested in templating or anything more advanced than that.
  3. Not something I want.
  4. Not something I want.
  5. Feel free to make such binary, but mining is not the goal of this rule.
  6. We could explore ways to make it more extendable, but I think this is taking it too far. I'm thinking more like allowing custom keywords like [custom-keyword:something].
  7. Not something we will do, but anyone could do this.
  8. This one we can do, but should be a separate issue and PR.

To be honest, I think you want a very different direction for this rule than we do, and it would probably be easier for you to create your own rule.

@brettz9
Copy link
Contributor

brettz9 commented Jun 30, 2019

Yup, does sounds like that. Though I do like the features you are adding, I'd like a lot more. So carry on, I'll leave you to it! :)

lubien added a commit to lubien/eslint-plugin-unicorn that referenced this issue Jul 6, 2019
Fixes sindresorhus#238

* Due date check.
* Own package version check.
* Dependency package version check.
* Dependency inclusion checks.
@issuehunt-oss
Copy link

issuehunt-oss bot commented Sep 4, 2019

@sindresorhus has rewarded $90.00 to @lubien. See it on IssueHunt

  • 💰 Total deposit: $100.00
  • 🎉 Repository reward(0%): $0.00
  • 🔧 Service fee(10%): $10.00

@issuehunt-oss issuehunt-oss bot added 🎁 Rewarded on Issuehunt This issue has been rewarded on Issuehunt and removed 💵 Funded on Issuehunt This issue has been funded on Issuehunt labels Sep 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement 🎁 Rewarded on Issuehunt This issue has been rewarded on Issuehunt help wanted
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants