-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
test: port test-format to typescript #20322
Conversation
function get_byte_units(guide_value: number, factor?: 1000 | 1024): ByteUnit[]; | ||
function format_number(n: number | null | undefined, precision?: number): string | ||
function format_bytes(n: number | null | undefined, factor?: 1000 | 1024 | string, options?: FormatOptions & { separate?: false } | false): string; | ||
function format_bytes(n: number | null | undefined, factor: 1000 | 1024 | string | undefined, options: FormatOptions & { separate: true } | true): string[]; |
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 want to veto this, this is a terrible API. We should not type how we don't want code to be written.
Passing factor as MB
and then reverse looking up that it was 1000 is awful imo and we should rid ourselves of it.
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 can accept this argument, but it leaves us in an interesting place: we test this behaviour, but want to make it statically impossible...
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.
One way we can do this is with as any
casts in the tests... not sure how I feel about it...
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.
My believe is that typing should help us uncover weird things, like the superuser: true
and we should then fix this
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.
Let's chat about this tomorrow. There's definitely a conversation to be had here...
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.
Just to be clear, "get rid of" could mean:
- completely remove this functionality from
cockpit.js
, breaking the API - remove the advertisement of this functionality from
cockpit.d.ts
, breaking only typescript users /** @deprecate */
the functionality incockpit.d.ts
- something else?
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'd like to actually break the API, given that there are zero known users; but I'm too scared about the unknown ones. So, my gut feeling:
- Design the API as we want it (see my proposal above, I'm happy to discuss of course)
- Do the types exactly for this, so that we learn about unintended API usage via type checks
- Then add some backwards compat hacks inside of
format_bytes()
to opportunistically interpret a non-object second argument: if it's "1024", treat it as{ binary: true }
, and ignore all others. console.warn() about it in any case.
Is that possible/reasonable?
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.
So here's one proposal that I think you might like, which would let us keep something like the existing podman case:
/* === Number formatting ===================== */
interface FormatFactor { _tag: "format-factor" }
type FormatOptions = {
output?: "value" | "unit";
precision?: number;
base2?: boolean;
factor?: FormatFactor;
};
function format_number(n?: number?, precision?: number): string
function choose_format_factor(n?: number): FormatFactor;
function format_bytes(n?: number?, options?: FormatOptions): string;
function format_bytes_per_sec(n?: number?, options?: FormatOptions): string;
function format_bits_per_sec(n?: number?, options?: FormatOptions): string;
and here's a simplified version that makes the podman case impossible:
/* === Number formatting ===================== */
type FormatOptions = {
precision?: number;
base2?: boolean;
};
function format_number(n?: number?, precision?: number): string
function format_bytes(n?: number?, options?: FormatOptions): string;
function format_bytes_per_sec(n?: number?, options?: FormatOptions): string;
function format_bits_per_sec(n?: number?, options?: FormatOptions): string;
I'd be OK with either.
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.
TBH I don't understand how the first proposal would work for "the podman case", by which I suppose you mean "uses the separate
option" -- it will return a string[]
then (or even before cockpit-project/cockpit-podman#1672 it would get a boolean third argument).
Also, for the second one, options
is really an object ({ precision: 3 }
), whereas in the first one the {}
feel more like the grouping for the various types that the second argument could have? (bool or int or string). This doesn't seem consistent?
(That said, I really dislike the current API; bool | int | string
is just crazy)
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.
The idea with the more complicated API is that you can use choose_format_factor(size)
to get an opaque FormatFactor
object which can then be passed as factor
to multiple invocations of format_bytes()
to force the same units from each invocation. You could then opt out of the display of the units with output: "value";
It was just an idea. I think I'd actually prefer not to do it.
I've split out the hopefully-less-controversial parts of this to separate PRs. |
This was mostly pain-free, except that it tests a very wide range of possible values to the format functions. Expand the type hints accordingly. There was one case that required a bit of a nudge — deepEqual wants both sides to be the same type, and one of them is very static in nature and the other quite dynamic — just use `as unknown` to force it down.
34fc613
to
dd99e07
Compare
function format_bytes_per_sec(n: number, factor: 1000 | 1024 | string | undefined, options: FormatOptions & { separate: true } | true): string[]; | ||
function format_bits_per_sec(n: number, factor?: 1000 | 1024 | string | undefined, options?: FormatOptions & { separate?: false } | false): string; | ||
function format_bits_per_sec(n: number, factor: 1000 | 1024 | string | undefined, options: FormatOptions & { separate: true } | true): string[]; | ||
function get_byte_units(guide_value: number, factor?: 1000 | 1024): [ByteUnit, ByteUnit, ByteUnit]; |
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.
FTR: There are zero uses of this outside of cockpit.git, and it's not documented. The only place that uses it is in cockpit/main/pkg/storaged/dialog.jsx . Let's make that private?
→ #20334 |
This was mostly pain-free, except that it tests a very wide range of
possible values to the format functions. Expand the type hints
accordingly.
There was one case that required a bit of a nudge — deepEqual wants both
sides to be the same type, and one of them is very static in nature and
the other quite dynamic — just use
as unknown
to force it down.