-
Notifications
You must be signed in to change notification settings - Fork 22
refactor: migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing #217
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
Conversation
Baroshem
left a 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.
Really amazing work did there! I like the new approach much better and cant wait for it to be released so that I could check if the issue with Zod could finally be solved in Nuxt Cloudinary.
I have left few comments/suggestions for you to see but overall, a solid work! Kudos!
| >( | ||
| def: PluginDefinition<asset, when, name, options> | ||
| ): TransformationPlugin<asset, when, name, options> => | ||
| ({ strict: false, ...def }) as never; |
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.
question: is this never intented?
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.
as never is just a slightly cleaner/safer way than as any to allow an assignment that TypeScript doesn't understand is safe.
I see a lot of people do something like as TransformationPlugin<asset, when, name, options>, but in the end you're just adding a lot of complexity for no additional safety.
| if (!success) { | ||
| if (process.env.NODE_ENV === "development") { | ||
| console.warn(`Invalid flag ${flag}, not applying.`); | ||
| } | ||
| return; | ||
| } |
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.
question: shouldn't we maintain this functionality? I think it is missing from a new approach
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 removed this based on feedback from @colbyfayock that we should be able to trust the input types to the functions themselves rather than performing runtime validation, which I think make sense if these flags are being invoked from an API directly.
If that's not the case, it would be easy enough to refactor those union definitions to tuples and then extract them back out to see if they're in the list, but in general I think the reasoning is good that if you have a typed API, you shouldn't need to revalidate all your inputs.
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 dont feel particularly strongly one way or another here. i always thought that providing more console.logs or throws that move errors closer to the developer could be helpful but not at the expense of trying to maintain something like zod, so moreso if there is good opportunity i think we should leverage it but not for any kind of significant overhead. this example was using zod, so it would need refactoring
@Baroshem any thoughts around that?
| @@ -1,22 +1,20 @@ | |||
| import { z } from "zod"; | |||
| import type { TransformationPlugin } from "../types/plugins.js"; | |||
| import { plugin } from "../lib/plugin.js"; | |||
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.
question: is this import correct? I can see that this file is plugin.ts in the file tree
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.
Yeah, that is the default method TS recommends to do modern ESM imports in Node. Always a bit of a point of confusion/contention :P
It's actually more viable now to do .ts as of 5.7, but .js is the more standard approach (also not changed in this PR).
| @@ -0,0 +1,38 @@ | |||
| export const isArray: (data: unknown) => data is ReadonlyArray<unknown> = | |||
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.
suggestion: Maybe it would be worth adding a JSDoc here explaining why this utility was created as at first glance it may not be understanadable and devs would need to jump here to understand why normal isArray function was not 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.
Makes sense, I'll add that. Array.isArray sucks for a couple reasons:
- Narrows the type to
any[] - Doesn't work with
readonlyarrays
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.
thats interesting - can't help to wonder if there's any kinda native workaround / future spec that'll address that kinda thing. perhaps it wasn't the main intent, but i used to always use Object.keys but i learned that Object.entries is better for TS. wonder if there's an equivalent either now or in the future? but maybe there's not much additional value that could be provided so its not worth the effort?
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.
Array.isArray would be much safer if it was defined like the version I implemented, but at this point it would be too big of a breaking change for TS since so much code is implicitly relying on that any ☠️
Luckily, there's no runtime overhead here as it's just a redeclared type with a reference to the original method.
Object.keys and Object.entries are a bit different. In those cases, TS has opted for the safe option by inferring a conservative type, but that isn't necessarily what you want if you have an object with known keys and want the narrowed types. That's what the entriesOf utility I added can help with.
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.
cool thanks david
|
lets get this into a beta branch! |
# [@cloudinary-util/util-v5.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v4.0.0...@cloudinary-util/util-v5.0.0-beta.1) (2024-10-18) ### Features * migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](#217)) ([f605f26](f605f26))
|
🎉 This PR is included in version @cloudinary-util/util-v5.0.0-beta.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
# [@cloudinary-util/url-loader-v6.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.5...@cloudinary-util/url-loader-v6.0.0-beta.1) (2024-10-18) ### Features * migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](#217)) ([f605f26](f605f26))
|
🎉 This PR is included in version @cloudinary-util/url-loader-v6.0.0-beta.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
# [@cloudinary-util/types-v2.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.11...@cloudinary-util/types-v2.0.0-beta.1) (2024-10-18) ### Features * migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](#217)) ([f605f26](f605f26))
|
🎉 This PR is included in version @cloudinary-util/types-v2.0.0-beta.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Description
This PR migrates the repo off of Zod schemas toward pure TS with JSDoc annotations that can eventually be used to extract metadata for display in docs.
Generally the external behavior should be identical, with obvious exceptions where schema entry points are no longer available etc., so this would constitute a breaking change for consumers relying on those entrypoints or whose inputs may no longer be valid with new type safety around video/image options.
I've also updated all the tests to
.tsso we can be sure the types for the API are working as we expect going forward.Although all the tests are passing, the doc generation issue remains unsolved, causing the repo-wide build to fail, so that will need to be updated to use a JSDoc parsing tool. However, it should be quite straightforward to wire that up in place of the previous Zod-embedded metadata.
For now, I'm opening this against the
betabranch so the required JSDoc parsing logic can be added and other changes can be experimented with before broader consumption.Issue Ticket Number
N/A
Type of change
Checklist
(Still a draft, need to figure out how to work around missing schemas in build)