-
Notifications
You must be signed in to change notification settings - Fork 57
Conversation
I'm new to flow, so my questions might be pretty basic. Setup
So the
As we use Babel anyway, I agree that using import/export syntax is a good idea.
So you run a watcher script on every package you've linked, right? That surely is an additional step and might have surprising consequences if you forget about/don't know that a module is a flow based one. But I think with some tooling it might be possible to run a single script from the repository you've linked from.
For me it's a must that things are as easy as possible for new-comers. If you get a stacktrace you should be able to look at exactly those files to fix the issue. I contribute a lot to random open source projects I happen to use. There it is very important that it's easy to get started, without knowing the exact setup for development. Issues
Once we agreed on things, I can help getting things work with Aegir.
I agree that it is important. According to a pull request on your repository Gozala/standard-flow#4 standard does now support flow. So this might be a non-issue.
I only know that documentation.js supports flow, which would make the JSDoc annotations less redundant. But I think that's a minor thing. As the current setup doesn't make the documentation worse, we can have a look later on if there are ways that it could improve the docs/make it simpler. My commentsWhat I'd like to see is that someone who has a first look at the library ideally doesn't need to have any idea about the tooling to fix simple bugs. A developer would only care about the To me it looks already pretty good with little pain points. Though I haven't worked in such a setup yet, so please chime in if I'm missing something. |
That is entirely for other packages depending on this and using flow. So when other package has
Sure it's additional step and one point or the other you might forget to do it, but not on every single package you linked, just packages you are making changes in. And you yes you probably could automate this by making watches watch every linked package but in my experience this problem was so rare that it did not bothered me enough to make such tool.
I am not sure which option do you feel is more appropriate here. I really only run into this if I run node repl and we could add
It did used to have that support in the past as well but it was really bad it was reporting issues where there were none and was completely ignoring type definition blocks see It seems there are still open issues: In fact @feross suggested to do standard-flow in first place to cover all this see: With that said I am happy to just use standard with a flow config as mentioned there, or use standard-flow, but I would really recommend giving prettier a chance as it just works and makes any style discussions obsolete, but then again that's not what I'm trying to sell here so whatever works for you, I can till secretly use prettier in my editor.
Yeah that's an intention
I think that's probably should be part of I'm also unsure about BTW
Please note that it's only really necessary if you're working in package |
@vmx BTW I'm not sure what the actionable todo list here is, if we could make one that would allow me to push forward. |
We (@Gozala, @victorbjelkholm, @vmx) had a discussion on IRC. I'll quickly post the most important outcomes:
|
I apologize for not following up on this sooner, just had some major things come up on other fronts that prevented me from this. I plan on updating this pull to do what @vmx summarized above today. |
- Added test/node which loads up source-map-support/register in order to get source-mapped error stacks in tests. - Run prettier + flow check in place of lint. - Use aegir config to use babel-loader for webpack builds. - Use different babel config for browser builds to avoid inlining source maps.
Overview / Notes of the followup changes
|
Thanks @Gozala that looks really good. Could we use prettier-standard instead of prettier? This way we should be able to use the standardjs linting + adaption to make it work with flow. |
I did run a prettier-standard and then followed the the instruction at https://standardjs.com/index.html#can-i-use-a-javascript-language-variant-like-flow-or-typescript:
The only complaints I got were:
It don't understand those, but I'm sure @Gozala can make sense of those. |
I have not personally used it but everything I used that tries to adapt standard to use with flow runs into the same incompatibility issue between choices standard and flow project made which shows up in different form:
I am sure with enough effort you could get a working setup, but then again as I described elsewhere fundamentally standard attempts to format and lint your code, where's prettier does just formatting and flow does type checking (which can be though of as linting) there for there are no overlap and no issues and outcome is mostly same.
My guess is that standard is not aware of built-in flow utility types P.S.: There is unfortunately no way in flow to import built-in types like that. |
To be clear I have no interested in solving issues between flow / standard incompatibilities for several reasons:
If you decide to stick to standard, so be it I'd rather just add |
@Gozala I've to explain why I was so keen on standardjs, it was due to a misunderstanding (sorry for that). I'm still new to modern JS toolchains. I though most of the linting came from the standardjs rules. But when I checked the code I saw that many of them come from AEgir (https://github.com/ipfs/eslint-config-aegir/blob/master/index.js). Also when I was talking about standardjs I actually meant "standardjs conform formatting" and not the formatter. Although I'm kind of interested being standardjs conform, surely being 100% conform shouldn't block this effort. Edit: Though I think using prettier-standard might be a good idea, on my machine the difference between the current code and the prettified one was quite OK (way less different that with the normal prettier) |
For me it looks good. Could someone with more experience have another looks to see if there's anything missing or if it is even good to go? /cc @diasdavid @victorbjelkholm |
You were not actually wrong as standardjs is essentially set of rules+tools on top of eslint. But then again linting is naive type checking and I really don't see much value in using linter along with type checker as they more likely that not going to disagree on something.
I don't want to leave an impression that I'm against standardjs or pushing for prettier. Just trying to provide my viewpoint formed by prior experience, but happy to back off and use whatever you folks choose, as long as I'm not forced to work out standard / flow incompatibilities. |
Agreed about types. I just want the additional linting (which is mostly ESLint setting set by AEgir, not standardjs) like wrong spacing, left-over console statements etc. I also would like (though I don't know if that's really important) to be able to put the "standardjs compatible" badge on it, so people can code that way and the result won't be much different from the prettier-standard run.
I really appreciate your experience with Flow. You spend already so much time on this, which is great. You don't have to care about small details like fighting Flow - standardjs incompatibilities. I'll take care of those issues. Though I might ask yout do adapt things when I find how ways to work around those incompatibilities (then I again feedback from you is again appreciated as I might find things that are not practical). So what I think is left is (please let me know if you disagree and/or don't find it important enough so that you want to spend time on these):
|
Could others (@diasdavid, @victorbjelkholm, @pgte) please chime for:
@pgte: If you've thought's about using Flow or the current state of things, feedback is appreciated. I don't think you need to read the full issue, just the current state of things. But please don't feel obliged, I just thought you might be interested in this topic. |
Reviewing this PR now and I've some questions, however, given the amount of information here I want to apologize in advance if these were already answered and I missed it. With this PR:
|
Shortly Yes! That is the reason why
Currently user needs to run
I'm not sure I do understand what you're saying here. But I also believe that browser test do run from |
prettier will take care of spacing during commit. I suppose no left-over I also would like (though I don't know if that's really important) to be able to put the "standardjs compatible" badge on it, so people can code that way and the result won't be much different from the prettier-standard run. I would just replace standard badge with prettier. Point of the prettier is really to get rid of formatting rules, don't even think about formatting prettier will make sure it's right. I'd frame it how much time / mental effort would you like your contributors to spend on formatting, prettier gives you none, with standard in my experience it more than none (flow makes it even worth).
Thanks for the kind words.
I personally question the benefits and worry of the incompatibilities that would still arise. That being said, but give the devotion to standard it's probably best to do just that.
I would prefer to leave this and AEgir side of things to someone else, but if this going to be blocked by that I'm willing to take a stab at it. It's just the whole thing started as I want to build something like Dat on top of IPFS and figuring out how to configure ESlint is so far from my primary objective that I have hard time incentivizing myself. |
I'm getting pretty convinced that this can indeed work for our entire module codebase. We will need an updated version of https://github.com/ipfs/community/blob/master/js-code-guidelines.md (it is about time anyway). @pgte @olizilla You have spoken some thoughts and concerns about injecting a type system. Could you go through all the notes and share with us your feedback? |
This is what I suspected :) I will take core of the "additional linting" part. I don't wont to over-stress your commitment for getting us into the typed world. |
My apologies for taking a while to come back here and thank you @Gozala and @vmx for keep pushing on this one :) I'm fairly happy with the answers I got so far, I would just like to see this transformation happen to a module that uses multihash (i.e js-cid, as planned in https://github.com/ipfs/community/issues/278#issuecomment-361002950) so that we can have a shared understanding how it all works across modules. This is also a significant change to push throughout the module codebase and so, I won't feel comfortable until I have heard at least from 2 or 3 more from the active JS contributors (@Stebalien, given your love for types, I would like your thoughts too :)). |
const bs58 = require('bs58') | ||
import bs58 from 'bs58' | ||
import varint from 'varint' | ||
import {names, codes, defaultLengths, type Name, type Code} from "./constants" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Gozala @vmx given that this enables us to do dynamic imports, does this mean that we finally can also do treeshaking? (ipfs/js-ipfs#951)
I'm cross linking @alanshaw comment on the same topic: https://github.com/ipfs/community/issues/278#issuecomment-361219723 |
@diasdavid as long as this doesn't introduce a high barrier to entry or make it difficult to using external libraries, I don't really have much of an opinion. |
@Gozala: I've some good news. After talking to several people. We want to give the Flow types a try. Thanks for all your work so far! I'll be leading this endeavour. I'll create a separate issue which will outline the plan and further discussions. |
I just created the issue for the Flow Awesome Endeavour. Further discussions about the general approach should take place there. The discussions here will be related to this specific PR. ipfs/js-ipfs#1260 |
"build:types": "flow-copy-source --verbose src lib", | ||
"build:lib": "babel --out-dir lib src", | ||
"build:node": "npm run build:types && npm run build:lib", | ||
"start": "flow-copy-source --watch --verbose src lib & babel --watch --out-dir lib src" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to also add the type checking to the npm start command? It would be nice to be warned if there are any type errors introduced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In practice there should be impossible to introduce type errors as that would fail In CI and there for won’t be merged.
Also given that initail run of type checking takes quite bit time I don’t think running that on start would be a good option.
@@ -0,0 +1,4 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this file is meant to be in this PR.
@@ -117,13 +129,13 @@ exports.decode = function decode (buf) { | |||
* @param {number} [length] | |||
* @returns {Buffer} | |||
*/ | |||
exports.encode = function encode (digest, code, length) { | |||
export function encode (digest:Buffer, code:Code, length:number):Multihash { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm working on converting js-multihashing
and I think that code parameter here should be code: Code | Name
export function encode (digest:Buffer, code:Code | Number, length:number):Multihash {
This PR is close to be ready. One thing I'd like to see is having it use prettier-standard instead, so that people will still have the source in the format they are used it. Ideally it's two separate commits. One doing one run of prettier-standard and the other one being this current PR. I'm happy to do that work myself, though it might slip into tomorrow. If anyone else wants to help out (even if it's later that week), please leave a comment, it would be appreciated. |
"lint-staged": "^6.0.0", | ||
"pre-commit": "^1.2.2", | ||
"prettier": "1.10.2", | ||
"rollup": "0.56.1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was rollup
introduced / where does it get used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wondered the same. I'm in the process of pushing an updated version of this PR. There I don't use the rollup module and it still seems to work.
"lint-staged": { | ||
"*.js": [ | ||
"prettier --no-semi --write", | ||
"git add" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had bad experiences with a lint-staged
configuration like this in the past. The main problem is that when you only stage patches of a file which get changed by prettier --write
afterwards the whole file is staged.
I didn't want to destroy this PR's history, hence I've created a new one, please review #49. |
Setup
src
into untyped code inlib
. I do not know how this setup would fit here, but that's most common one I have seeing so I though it was most reasonable (although it seems to have some problems with current setup, more on that in issues sectionsrc/*.js
intolib/*.js.flow
, it might be confusing but it actually provides some flexibility when working with many packages, because flow follows the same module resolutions algorithm as node exceptfile.js.flow
takes precedence overfile.js
so this setup enables node to ignore type annotations while flow use type annotations. While it is possible to tell flow to look intosrc
instead it needs to be done per project directory containing.flowconfig
which implies every user of library would need to do that to get type annotations so it's more convenient to use this approach instead.import
/export
syntax. Flow does have some limited support forexport.
/require
but it's not idiomatic and those modules can't be imported which won't play well with rest of the flow ecosystem. Also since there is still a babel step to remove type annotations it did not seemed there was much value in sticking torequire
, but if needs to be this could be changed back torequire / exports.
.npm start
will track changes insrc
and will automatically reflec them inlib
. This makes work with multiple linked packages comparable to working with liken packages that are in pure js, whith only diff that you need to runnpm start
in the packages you're making changes in.Issues
aegir
is configured here. I did not find.aegir.js
file so I assume default are used here, which unfortunately:src
. Not sure if moving typed code elsewhere and emitting untyped intosrc
makes more sense or configuringaegir
differently instead.npm test
to do type checking as well. I tried to getaegir
somehow runflow check
but without success, so instead I've addedflow check
into.travis.yml
but I don't think that makes much sense. I think running type checker before submitting pull is probably a good idea.aegir lint
this is unfortunately a problem I did not expect and according to @victorbjelkholm is very important. From what I understand you use http://standardjs.com/ which unfortunately does not support flow out of the box. So in the past after discussing it with a standard team I end up making standard-flow. Which kind of worked but I'm not sure how to plug it intoaegir
. I also tried to make argument towards https://prettier.io/ which can be configured to output code if not fully standard compliant at least one that I can't distinguish, it handles types much better than standard does and is also output is consistent regardless of input, in my experience standard often preserves input which can lead to not really standard output which still lints. It's also worth mentioning that standard provides bunch of lint rules that are extremely helpful but redundant and sometimes get in your way when working type checker, since later has much better understanding of code.aegir docs
seems to generate docs although it seems to ignore flow type annotations. Again I'm guessing it is a config problem somewhere, but I'm not sure where or how to change that. It is also worth pointing out that I have mixed success using http://documentation.js.org/ for doc generation, if I recall correctly imported types from other libraries were sort of opaque. That being said it's probably not going to be better than without annotations anyway.Notes
export type Multihash = Buffer
that does not really do anything other than allow us to add semantic info that it's not justBuffer
but rather it is one that representsMultihash
. In the future I would like to use nominal types which would actually type check thatMultiphash
is passed rather than arbitraryBuffer
but after discussing this with @vmx on IRC we concluded it's probably best to do it in the next step.codes
,names
anddefaultLength
are now typed such thatnames.foo
will be a compile time type error, property would have to match one of the names supported. In factcoerceCode
does that too now. It kind of makes runtime checks obsolete, but disabling those would make only sense if users of this library also type-check.isAppCode (code:number):boolean
andisValidCode(code:number):boolean
are instances of the functions that aren't very type friendly. I had lengthy discussion about this with @vmx on IRC. Problem is that for type checkerif (isValidCode(code)) { code }
predicate does not really refine type ofcode
in the if block. Type friendly version would be something like:toCode
isn't really important, it's just from the return of that function type checker knows thatcode
is eithernull
orCode
and since it's notnull
it isCode
. I would like to exposetoCode
andtoAppCode
style functions along with predicates otherwise every use of predicate would be forced to do this to type-check (and you want to reduce usage ofany
as much as possible):