-
Notifications
You must be signed in to change notification settings - Fork 4
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
Satisfy minimum requirements for full typescript project #37
Conversation
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.
Ok we are almost there I think!
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.
Nice! Left some comments, I think they are quite clear, and I will let the @sodic take over the PR review and do the final accept, since we are getting more into TS types and he knows this stuff better. I will be lurking so I can see the final result and learn.
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 am giving a neutral "comment" to remove my "request changes", so that @sodic can do the final approve when he finds it fit.
@@ -12,19 +11,44 @@ import { generateCohortRetentionReport } from "./cohortRetentionReport"; | |||
// they are prepared (our events removed, sorted) and that they are all events available for CLI, | |||
// for the whole history. You should obtain them with fetchAllCliEvents(), in that case they will | |||
// be all good. | |||
export async function generatePeriodReport( | |||
export async function generateFullPeriodReport( |
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.
What about typing these guys also? Or are we leaving this for later?
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 do that now.
src/analytics/reports/index.ts
Outdated
|
||
type ReportName = string; | ||
|
||
export type SimpleReport = { |
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.
If I am correct, we have these individual report files importing from this index file, because they need SImpleReport, but then we also have this file importing from them because it is using them. So we have a cyclic dependency. I know JS can suffer those to a degree, but still, might be good to avoid it. Therefore, I would consider extracting SimpleReport into separate file, simpleReport.ts .
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 would also restructure then.
We have maybe too much files in the reports folder, and also the fact that both simpleReport
and totalReport
are located in the same reports
directory. The naming indicates that they are similar, but one is only a type while the other is an actual report. The current structure is a bit weird. I wanted to do that in next PR but we could change it 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.
I don't really mind that one has type and another does not though, types and functions are all important. Ideally files would be organized by domain. I would break the circ dep here now immediately, and then in the next PR you can try to improve the structure further if you wish.
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'll just wait for @sodic to give his opinion on types (they might change completely), and after that, if it's still a circ dep I will break 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 figured out what's bothering me here.
Partial<SimpleReport>
is a supertype of all reports, but its name suggests otherwise. And pureSimpleReport
isn't use anywhere except to define other types.SimpleReport
's name is derived fromCompositeReport
(i.e., because there's a composite thing, this is simple thing)- The relationship is defined backwards - it's the printing that requires this interface, not the reports.
- The
string
in[reportName: string]
should be bounded. The entire type is probably underspecified.
This is a sketch of how I'd expect the type definitions to look like:
export type GenericReport = Partial<{
text: string[];
csv: (number | string)[][];
chart: ImageCharts;
}>;
export type CompositeReport = PeriodReport | TotalReport;
type TotalReport = {
totalReport: Pick<GenericReport, "text">;
}
type PeriodReport = {
cohortRetentionReport: CohortRetentionReport;
userActivityReport: UserActivityReport;
projectsReport: ProjectsReport;
};
export type CohortRetentionReport = Pick<GenericReport, "text">;
export type UserActivityReport = Pick<GenericReport, "text" | "csv" | "chart">;
export type ProjectsReport = Pick<GenericReport, "text" | "csv">;
I might have missed something as I'm still not 100% familiar with the code, but these types convey an explicit structure and tell a story. Ideally we'd also colocate them.
@FranjoMindek Try to work this in and let me know if you need help. We can have a call tomorrow (today :))
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.
@FranjoMindek did a bit more of reviewing!
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.
Nice work! Left some comments, will come back with more probably :)
src/analytics/charts.ts
Outdated
import ImageCharts from "image-charts"; | ||
|
||
export type ChartData = { | ||
series: Record<string, number[]>; |
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 FYI, no need to change. Read this and pick your preference: wasp-lang/wasp#1235 (comment)
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 like the idea of having different intents with records and index signatures. Though, for that to work the whole team must be educated on it. Personally, I like 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.
Glad to hear it! Time for an inquisition then :)
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.
You put in a rocket here but didn't change it. Forgot to push something?
|
||
// Expects data to be: | ||
// data = { series: { name: [number] }, periodEnds: [string] } | ||
// Returns a string, URL leading to image-charts.com that contains query with exact | ||
// instructions how to display this chart via image. | ||
export function buildChartImageUrl(data, title, type = "line") { | ||
const chart = ImageCharts() | ||
export function buildChartImageUrl( |
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 know we're typing this in the next PR, so no changes necessary here.
Still, FYI: wasp-lang/vscode-wasp#6 (comment)
src/analytics/reports/index.ts
Outdated
export { fetchEventsForReportGenerator } from "./events"; | ||
export { generateTotalReport } from "./totalReport"; | ||
import { generatePeriodReport } from "./periodReport"; | ||
|
||
type ReportName = 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.
Unbranded type aliases can be avoided/improved in most cases. This is usually desriable because aliases can give a false sense of type safety and obfuscate primitive types.
In this case, it's used to name a Record
's key. A better way to do this is an index signature:
export type CompositeReport = { [reportName: string]: Partial<SimpleReport> };
Further reference: wasp-lang/wasp#1235 (comment)
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.
Apologies, I forgot to mention this in writing.
I have a strong feeling the key type should be a bounded subset of string
. Is that right?
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.
Finally got around to it :)
type BasePeriodReport = { | ||
userActivityReport: UserActivityReport; | ||
projectsReport: ProjectsReport; | ||
}; | ||
|
||
export type AllTimePeriodReort = BasePeriodReport; | ||
|
||
export type PeriodReport = BasePeriodReport & { | ||
cohortRetentionReport: CohortRetentionReport; | ||
}; |
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.
What's going on here, why is the all time report different than the period report?
Also, the names seem to off:
AllTimePeriodReport
sounds like a specialization of aPeriodReport
but it isn't, meaning thatPeriodReport
is also missing some kind of a prefix (or thatAllTimePeriodReport
shouldn't havePeriod
in it)- After fixing that, I believe the
Base
prefix onBasePeriodReport
becomes unnecessary.
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.
That is a bit weird relationship.
PeriodReport
is a general report over a period of time.
AllTimePeriodReport
is ?variation? of PeriodReport
which excludes CohortRetentionReport
because of it's complexity. This is because a period report which spans the whole timeline has too much data.
Maybe PeriodReport
and AllTimeReport
?
If it's true that they share part of reports by accident (they both relate to the time domain) but are actually different, it would be best to extract AllTimeReport
to a different file?
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.
Now that I look at it TotalReport
also covers the whole period of time. There is again some overlap.
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.
Report restructuring was decided as separate PR
src/analytics/reports/index.ts
Outdated
export { fetchEventsForReportGenerator } from "./events"; | ||
export { generateTotalReport } from "./totalReport"; | ||
import { generatePeriodReport } from "./periodReport"; | ||
|
||
type ReportName = 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.
Apologies, I forgot to mention this in writing.
I have a strong feeling the key type should be a bounded subset of string
. Is that right?
src/analytics/reports/index.ts
Outdated
|
||
type ReportName = string; | ||
|
||
export type SimpleReport = { |
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 figured out what's bothering me here.
Partial<SimpleReport>
is a supertype of all reports, but its name suggests otherwise. And pureSimpleReport
isn't use anywhere except to define other types.SimpleReport
's name is derived fromCompositeReport
(i.e., because there's a composite thing, this is simple thing)- The relationship is defined backwards - it's the printing that requires this interface, not the reports.
- The
string
in[reportName: string]
should be bounded. The entire type is probably underspecified.
This is a sketch of how I'd expect the type definitions to look like:
export type GenericReport = Partial<{
text: string[];
csv: (number | string)[][];
chart: ImageCharts;
}>;
export type CompositeReport = PeriodReport | TotalReport;
type TotalReport = {
totalReport: Pick<GenericReport, "text">;
}
type PeriodReport = {
cohortRetentionReport: CohortRetentionReport;
userActivityReport: UserActivityReport;
projectsReport: ProjectsReport;
};
export type CohortRetentionReport = Pick<GenericReport, "text">;
export type UserActivityReport = Pick<GenericReport, "text" | "csv" | "chart">;
export type ProjectsReport = Pick<GenericReport, "text" | "csv">;
I might have missed something as I'm still not 100% familiar with the code, but these types convey an explicit structure and tell a story. Ideally we'd also colocate them.
@FranjoMindek Try to work this in and let me know if you need help. We can have a call tomorrow (today :))
projectsReport: ProjectsReport; | ||
}; | ||
|
||
export type AllTimePeriodReort = BasePeriodReport; |
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.
This guy has a typo.
): Promise<PeriodReport> { | ||
const events = prefetchedEvents ?? (await fetchEventsForReportGenerator()); | ||
|
||
const basePeriodReeport = await generatePeriodReportBaseReports( |
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.
Typo in "reeport"
The problem of export type CompositeReport = PeriodReport | TotalReport | ...; Is that when we have a function which accepts In the end:
|
export interface TextReport { | ||
text: 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.
report specific functions will also go 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.
Looks good!
Don't forget to take care of the restructuring in a different PR :)
This is satisfying all
tsc
andeslint
requirements when we convert each of thejs
files tots
.Rest of changes will be in further PRs
Contains:
logger.ts
has been fully changed, due to using invalid constructor syntax.discord-bot.ts
let
->const
where no reference changecli.ts