-
Notifications
You must be signed in to change notification settings - Fork 42
[ RFC ] What changes would you like to make to the hhast-lint.json format? #287
Comments
I like this suggestion. Perhaps we could tag each new linter with the HHAST version in which it was added (or really any incremental number, since the HHAST version might not be known at the time a linter is added), then people could specify max linter version in their config. That way people could update HHAST itself without causing new lint errors, then later bump the linter version number if/when they're ready. That said, it's probably not too hard to update HHAST + immediately add any new linters to disabledLinters until they're ready to deal with the errors.
I'm not opposed to this but I can't imagine how we'd decide which linter goes in which group (like you said, right now it's unclear what should be default, if we have more groups it will become even more confusing). I wonder if we should just have "all". I expect most people would have 1--2 linters they don't like but they are unlikely to be the same ones for everyone, so everyone'd just use disableLinters? (+ maybe the version number) |
This discussion should be tied to (not merged with) #279 :) |
I strongly disagree with this for One of the proposed alternatives to 'all' and 'default' could be better
Definitely; initially, it was "is something like this needed for FB projects", but it's drifted and pretty arbitrary now.
I believe this is currently always a bug; the exception I expect at some point is completely contradictory linters - e.g. "always use
Perhaps get rid of
This is a valid use case for it, but FWIW, it's made for people who want to gradually start linting their codebase, moving to
#13 :) That said, now the AST's moving again, I'm not sure how viable third-party repositories of linters are, and this impacts the 'default' vs 'all' discussion: if we strongly disagree with the intent of a linter, but know some people really want it, it's well-written, should we accept or reject the pull request? Should it be included in whatever our "recommended" set is, whether that's "default" or "all-x.yy" ? Practicality of third-party repositories does change this, but the need for new codegen can be a pain. I'm going to add another one of these: Should HHAST be split up in to
|
More specifically:
|
... and none of the version numbers - even majors - need to match. |
In that world:
|
So, regardless, we're going to end up with some concept of "we recommend this set/configuration for new projects if you don't want to whitelist specific ones"; it's basically the same problem whether that means:
I don't think there's a good answer here: linters are not for soundness, they are for enforcing stylistic choices, which are fundamentally subjective. Even the ones that exist pretty much to highlight common mistakes have a counterpoint of "(I know what I'm doing|we idiomatically use them in a safe way), and we like writing code that way". The FB internal approach is "anyone can turn it on, and if there's too much push-back it gets disabled/limited", which won't work here. If we split out the linters to a separate package under facebook/ , perhaps "this matches FB coding standards and would be an appropriate linter at FB" is the correct separator; problems are:
This has non-style factors, such as how much 'good' code it complains about, and whether it's autofixable |
There's definitely some extra maintenance work for each project right now (e.g. an AST change in HHVM requires new HHAST release + potentially a new release of anything else that depends on HHAST like definition-finder, which would now include hhast-tools and hhast-linter). If we proceed with the plan to merge some projects into a "monorepo" that we've been discussing, that would make it easier (assuming we have good automation to publish a release of each project from the monorepo). |
Fair - I"m hoping that "just update hhast-lib without enabling more linters" in downstream projects would offset that |
Splitting hhast up into linters, tooling, and core would be the right thing to do for projects that want to depend on hhast. I am torn on the maintainability question. This discourages adding things like this into hhast-lib and may lead to people placing functions like this as free standing functions into hhast-linters instead to reduce dependency hell. |
One thing I would like to note, since HHAST liners are a "tool" ( not a library to use or build upon ), its okay to have internal BC-breaks, such as changing class names or architecture structure. however, this shouldn't affect projects that disable linters. therefore, I suggest that each linter now implements a new method |
Some form of name spacing is desired so that third party linters can be created independently of each other without risk of conflict with other linters, bundles or not. Having this be distinct to the FQN feels like solving the same problem twice For conciseness, it does support a configuration equivalent to “use namespace” |
the linter name itself can be prefixed, e.g: with official linters ( e.i ones shipped with hhast ), not using prefix, e.g: |
Also, it would be nice to have to ability to disable a linter within a linter. e.g: |
The intent is for bundled linters to be less special than they currently are; unprefixed is done for suppression as the odds of collision on the same line/node are somewhat low |
Pretty strongly against this: I do not think users would expect installing a library to disable linters they currently have enabled. |
it is possible for hhast to inform the users that 2 linters conflicts with each other and the user can decide on which one to use ( hhast can update the configuration file itself, and not run until the conflict is resolved ). making things harder for end-users is not a good thing. and having third party libraries reimplement their own runner to provide a better DX, is also not the best idea. |
Inversely, adding linters can not be fully automatic, and will need an explicit opt-in for security: installing a library should not lead to code execution without any extra steps. This also applies to HHAST itself, which is why the vscode (and previously atom) plugins prompt the user before executing it. |
I don't think so. when installing a set of linters that ensures enum members use camel case over shout case, I would expect it to disable the shout case linter. |
Conflicts and a resolution flow would be OK, as long as it’s pure data (e.g in vendor/foo/bar/hhast-lint.json), no code execution or configuration changes until user says yes |
Say a library I make gets taken over by someone malicious, and they add a fake linter that’s actually a Trojan but says it’s a naming convention change linter. Code can not automatically tell the difference between this and a real one. I would agree for user expectations when explicitly installing a conflicting linter, but that can’t be distinguished from malicious cases - or changing the project naming linter because of a non-linting libraries preference. |
(While yes, updating a library does change the code you’re executing, opening an editor to review those changes does not automatically execute them - when HHAST’s involved, it does) |
in this case, being able to disable or enable linters should be the latest concern, libraries can define scripts to run once they are installed in
or even better, can replace your library's binary ( IMO, the best way to go about this is as follow:
$ composer update
// updates
[HHAST] The following linters conflict with each other:
- [1] `FooBarLinter`
- [2] `BazQuxLinter`
Please choose which one to use: | After the user has chosen, hhast should update the configuration file to fix the conflict once and for all. |
This feature will almost certainly not be supported in whatever we eventually replace composer with. A potential security issue elsewhere does not make knowingly introducing another one OK.
Only an issue of code from that file is executed. Pseudomains are also going away
Again fine with this existing as long as it is purely data-based, with all code for resolving them being in HHAST itself - or at least HHAST prompting user before any third-party code is executed |
Not tested right now, but at least as of 2018 composer only runs post install scripts for top level projects, and didn’t for dependencies for similar security concerns - composer/composer#1193 |
there's always a workaround. it's possible to turn your stolen library into a composer plugin and hijack composer downloader ( https://github.com/symfony/flex/ ), or hijack composer autoloader ( https://github.com/ircmaxell/PhpGenerics ). |
Back to the original question, I'd add:
|
Coming back to here because of
'default' is currently pretty close to error + codesmell + some fb-style; I'm not sure if that's a good default, but if so, it should be explicit. 'error + codesmell' would be a more objective default, but less useful. I'm not sure what's best. There should be additional style linters that are not part of fb-style, but it shouldn't be possible to enable 'all': style linters can reasonably have exactly opposite viewpoints/recommendations. 'all' should be removed: it exists because of the incorrect assumption that projects would actually want to enable all linters - or, more specifically, that FB projects would. This implies that HHAST shouldn't merge linters that FB projects don't want. This is my mistake in the original design, we should be more open.
I also philosophically don't like the idea of a 'fb-style' built-in, but:
|
default etc: those could also be versioned (as discussed previously), optionally, and it would be nice to be able to specify different constraints. For example, I might want:
|
Why do we configure linters in a JSON file? Shall we allow the users to create their own functions to select lint rules, for example, a Hack file as the configuration, similar to PAC? |
Sure, though that's a bit tangental; regardless of how they write the configuration, we should provide better groupings and versioning data. Historically:
Specifically JSON over other formats like JSONC, YAML, TOML: HHVM has very few built-in data formats. There's serialize(), json, and INI files (if you want exactly PHP's semantics for INI files). JSON seems like the clear winner there; there also weren't really other viable options in the ecosystem. |
no need to, a neat solution would be is to introduce a new binary, call it "hhast-installer", executing this binary will create a new binary in your desired directory ( default to tools/hhast, or bin/hhast ) with the following content: #!/usr/bin/hhvm
namespace Tools;
use namespace HHAST;
<<__EntryPoint>>
async function main(): Awaitable<noreturn> {
$config = HHAST\Config::create()
->withFoo()
->withBar('bar')
;
await HHAST\Application::run($config);
exit(0);
} users can then edit that newly created binary to customize HHAST, and execute it instead of Libraries would need to add this generated file to their .gitattribute as |
This doesn't solve the problem for top-level projects (e.g. executables or websites); it would also need ignoring in |
On the other hand, the same's true for tests/ dev-depends on hacktest and fbexpect, and that's somethign we all live with. |
was gonna say that, it should be dealt with the same way people deal with tests/ and other files, strip them from production build. |
I don't understand this. Linting is simply another type of tests that can be executed by the IDE continuously. If |
also, it would be nice to make $input = IO\input_handle();
$output = IO\output_handle();
$application = new HHAST\Application($config);
await $application->run($input, $output); This was it would be possible to test the output of hhast in hhast itself, using MemoryHandle as input/output. |
if it's a generated entrypoint like @azjezz suggests, it's not an issue Otherwise the difference would be whether it's "execute all lint configs you find" vs "there must be exactly one" |
This is already supported if the LinterCLI is directly constructed instead of using the |
For manual execution of |
That IMHO, is annoying, i would rather run |
I don't think this is the right model; I don't think you're concretely suggesting that lint configs extend HackTest, but IMO if they go in However, they are not automatically-ran unit tests in IDE mode: HHAST is a full language server, a long-running process with request/response communication with the IDE. It's closer to I also consider the need to pass a path to Similarly, I don't want different behavior for IDE and CLI users; these should generally behave identically, and also the same as CI (which is largely CLI, but with the arguments being fixed). -- Also, I'm going to ask for github discussions to be enabled in this repository, then we need to split this up a bit :) I think there's three main questions, and we're trying to discuss them all in one thread:
|
I'll withhold my input until discussions are enabled. This whole thing went by pretty fast and I can't quite follow along. |
|
Closing in favor of https://github.com/hhvm/hhast/discussions |
I'd like to rethink the hhast-lint.json config settings, since there are some short comings.
Here is just a short list of properties that I'd like to have, in no particular order.
This is not an issue that is meant to be implemented; it is meant to start a discussion.
Updating HHAST should not cause more linters to be activated (causing failing travis builds).
When upgrading hhast versions, linters that have been written for that version are automatically turned on. This makes upgrading hhast (which you are sometimes required to do, because of hhvm AST changes) a more painful process than it should be.
There should be more granularity in the built-in linters than 'none' | 'default' | 'all'
Currently
all
, doesn't mean all linters.The only way to know that you are missing these linters is by digging into hhast and finding little gems like
NoEmptyStatementsLinter
orFinalOrAbstractClassLinter
.They might have been left out of the
all
option (NON_DEFAULT_LINTERS in the source) by mistake.The
default
option currently excludes 8 linters, but it is not clear what makes a linter non-default.The
none
option is made for people who require a stable output from their linters and who do not want and upgrade to introduce more linters that their code will fail under.These people will list out every single linter they care about, one by one, and they will not be made aware of new and exiting linters.
A hhast-lint.json file that is valid in version B should be valid for version A, even if linters that are declared in the hhast-lint.json file are not present.
Currently, when you name a linter that does not exist, you get this error:
Expected type 'Facebook\HHAST\BaseLinter', got type 'string'
This stops HHAST dead in its tracks, since it is an uncaught exception.
I'd like for HHAST to report that linter X could not be found and continue linting with the rest of the linters.
I would be nice to be able to refer to groups of linters, instead of individual linters.
I'd like to be able to define
Lexidor's pedantic linter pack: 1.4
,Fully autofixable linters: *
,Code style linters: 0.8
and have that be recognized by hhast.I would like to introduce a new hhast-lint.lock file.
This would allow us to:
The text was updated successfully, but these errors were encountered: