Skip to content

Conversation

@ssalbdivad
Copy link

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 .ts so 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 beta branch 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

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Fix or improve the documentation
  • This change requires a documentation update

Checklist

(Still a draft, need to figure out how to work around missing schemas in build)

  • I have followed the contributing guidelines of this project as mentioned in CONTRIBUTING.md
  • I have created an issue ticket for this PR
  • I have checked to ensure there aren't other open Pull Requests for the same update/change?
  • I have performed a self-review of my own code
  • I have run tests locally to ensure they all pass
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes needed to the documentation

Copy link

@Baroshem Baroshem left a 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;

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?

Copy link
Author

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.

Comment on lines -184 to -189
if (!success) {
if (process.env.NODE_ENV === "development") {
console.warn(`Invalid flag ${flag}, not applying.`);
}
return;
}

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

Copy link
Author

@ssalbdivad ssalbdivad Oct 18, 2024

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.

Copy link
Collaborator

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";

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

Copy link
Author

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> =

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.

Copy link
Author

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 readonly arrays

Copy link
Collaborator

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?

Copy link
Author

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.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool thanks david

@colbyfayock
Copy link
Collaborator

lets get this into a beta branch!

@colbyfayock colbyfayock merged commit f605f26 into cloudinary-community:beta Oct 18, 2024
github-actions bot pushed a commit that referenced this pull request Oct 18, 2024
# [@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))
@github-actions
Copy link

🎉 This PR is included in version @cloudinary-util/util-v5.0.0-beta.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

github-actions bot pushed a commit that referenced this pull request Oct 18, 2024
# [@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))
@github-actions
Copy link

🎉 This PR is included in version @cloudinary-util/url-loader-v6.0.0-beta.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

github-actions bot pushed a commit that referenced this pull request Oct 18, 2024
# [@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))
@github-actions
Copy link

🎉 This PR is included in version @cloudinary-util/types-v2.0.0-beta.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants