-
Notifications
You must be signed in to change notification settings - Fork 147
Demonstrate JSON Schema as source of truth for web-features data #2990
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
base: main
Are you sure you want to change the base?
Conversation
new.quicktype.ts
Outdated
@@ -0,0 +1,208 @@ | |||
/** |
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.
newtypes.ts
Outdated
export interface WebFeaturesData | ||
extends Pick<QuicktypeWebFeaturesData, "browsers" | "groups" | "snapshots"> { | ||
features: { [key: string]: FeatureData }; | ||
} | ||
|
||
export type FeatureData = Required< | ||
Pick< | ||
QuicktypeMonolithicFeatureData, | ||
"description_html" | "description" | "name" | "spec" | "status" | ||
> | ||
> & | ||
Partial< | ||
Pick< | ||
QuicktypeMonolithicFeatureData, | ||
"caniuse" | "compat_features" | "discouraged" | ||
> | ||
>; |
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 is a preview of what's coming when we add redirects. TypeScript and JSON Schema's type systems aren't strictly equivalent, so quicktype will generate correct but overbroad types. In this module, I'll pluck out some nuances (and badly generated names) that quicktype doesn't handle very well and clean them up by extending the generated types. While it's a bit weird looking, the benefit is that we can't completely diverge from the underlying JSON Schema.
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.
Do the TypeScript error messages if you get types wrong end up looking completely bizarre with this layering?
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.
They're not quite as nice as plain, from-scratch types but they're probably above-average in terms of informativeness in type error messages. I've seen some { … } & { … } & { … } & …
monstrosities and this is nicer than that.
newtypes.ts
Outdated
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
const t1: FeatureData = { | ||
name: "Test", | ||
description: "Hi", | ||
description_html: "Hi", | ||
spec: "", | ||
status: { | ||
baseline: false, | ||
support: {}, | ||
}, | ||
}; |
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 we like, we can even "test" some properties of our types—like I do here demonstrating a FeatureData
object without any of the optional fields—by instantiating some objects and letting the typechecker complain if we get it wrong.
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 seems like a useful smoke test. I guess that when we load the JSON and interpret it as a TypeScript type, there's no checking going on that we could rely on? That would be helpful, but I suspect it's not a thing.
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.
We could do this, but I'd prefer to avoid it on the initial implementation. Quicktype can generate zod runtime type check code, but it'd be a new dependency that I don't feel especially ready to embrace just yet.
schemas/new.schema.json
Outdated
@@ -0,0 +1,302 @@ | |||
{ |
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.
And here is the JSON Schema, intended for a human (me) to work with, instead of the generated JSON Schema. Mostly, things are ordered in a more readable way.
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 it! By now I can almost read JSON Schema, and I find this quite readable.
7c9c780
to
9846b90
Compare
I think we should do it! I'd rather have ugly TypeScript definitions than ugly JSON Schema. |
"$ref": "#/definitions/URL" | ||
} | ||
} | ||
}, |
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.
FYI: name and spec were previously marked as required. Now they are optional. Not sure if this was intentional.
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.
Fixed in b2b6762.
], | ||
"type": "object" | ||
"description": "Whether a feature is considered a \"Baseline\" web platform feature and when it achieved that status", | ||
"$ref": "#/definitions/StatusHeadline" |
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.
Similar comment here. baseline and support were previously required. But I think they should stay required. (Probably in StatusHeadline)
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.
Fixed in b2b6762.
schemas/data.schema.json
Outdated
"status" | ||
], | ||
"type": "object" | ||
"required": ["name", "description", "description_html", "spec"] |
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.
Is status no longer required?
"required": ["name", "description", "description_html", "spec"] | |
"required": ["name", "description", "description_html", "spec", "status"] |
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.
Fixed in b2b6762.
Thank you for the review, @jcscottiii. Thanks to your review I was able to find some other constraints that weren't in the new schema file. This also prompted me to discover some oddities in the rolled-up TypeScript types in npm package — I'm still working on fixing that part. |
I tried out the latest updates and it looks really good now! Thanks |
"types.d.ts", | ||
"types.quicktype.d.ts", | ||
"index.js", | ||
"data.json", | ||
"data.schema.json" | ||
], | ||
"scripts": { | ||
"prepare": "tsc && rm types.js && tsup ./index.ts --dts-only --format=esm --out-dir=." | ||
"prepare": "tsc && rm types.js && rm types.quicktype.js" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^24.0.7", | ||
"tsup": "^8.5.0", | ||
"typescript": "^5.8.3" |
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 thing I discovered in following up @foolip's #2990 (comment) question about type errors for consumers:
tsup
adds another layer of name-mangling, on top of the layer given by converting JSON Schema to TypeScript (via quicktype
). For example, as originally configured, FeatureData
is shown as extending FeatureData$1
. Ugly!
To fix this, I just let plain TypeScript generate the type declaration files. It's slightly less tidy — we have to include the types.d.ts
and types.quicktype.d.ts
files — but it's a very tiny hit for consumers (two additional small files and two development-time file reads for TypeScript consumers) and a nice boon for us (one fewer dependency and one less layer of indirection).
This also makes it a lot easier for us to do some other things in the future (e.g., adding util functions or making this a "normal" monorepo where we're doing less magic with the web-features
package).
Commit 6e383ff LGTM, less code and still works! |
This PR demonstrates switching from generating JSON Schema to authoring a JSON Schema. This is a prerequisite for #91 and fixes #2722. I'll self-review to point out some interesting things.
This NOT ready to merge. Don't merge it! If we want to go down this route, then there are a few tasks remaining to get this into a mergeable state: