-
Notifications
You must be signed in to change notification settings - Fork 885
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
Draft: Rewrite Schema #8479
base: v11
Are you sure you want to change the base?
Draft: Rewrite Schema #8479
Conversation
|
Size Report 1Affected Products
Test Logs |
Size Analysis Report 1This report is too large (678,434 characters) to be displayed here in a GitHub comment. Please use the below link to see the full report on Google Cloud Storage.Test Logs |
/** Optional. The description of the property. */ | ||
description?: string; | ||
/** Optional. Whether the property is nullable. Defaults to false. */ | ||
nullable: boolean; |
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.
nullable
means that the value can be undefined
, not null
, 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.
FYI this isn't a JS concept of nullable, it's you giving a schema to the model to fill in (whether you're asking it to do function calling or give you a JSON response), and you're telling the model whether it's ok to return this field to you with a value of null. I don't think non JS languages have undefined so I think it's just null. So if you say "required: true" and "nullable: false" that means, you have to fill out this field when you send it back to me, and it can't be null. "required: true"/"nullable: true" I think means, "this field needs to be in the JSON and it needs to be filled with some actual value". Actually JSON is JS I guess, but the official spec says "undefined" isn't a valid JSON value, just null.
} | ||
|
||
/** Converts class to a plain JSON object (not a string). */ | ||
toJSON(): Record<string, 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.
Why do we name this toJSON()
if it returns a plain JS object? Is this an API requirement?
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'm not sure what the best name is - this is an intermediate object between the very abstract Schema, where all the children are Schemas, and a JSON string - it's a plain JS object or POJO, could call it toPOJO()
? I have this instead of going straight to the stringified JSON because it's easier to inspect and debug.
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.
Oh, I was wrong, toJSON() actually should not return a JSON string, it should in fact return a JS symbol that is ready to pass to JSON.stringify(). Changing this back. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#tojson_behavior
const obj: Record<string, unknown> = {}; | ||
for (const prop in this) { | ||
if (this.hasOwnProperty(prop) && this[prop] !== undefined) { | ||
if (prop !== 'required' || this.type === SchemaType.OBJECT) { |
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.
Why do we only include therequired
property if this.type
is SchemaType.OBJECT
?
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 has been overhauled - the Schema proto actually sets "required" as an array on "object" type Schema only, and each member is the string name of a required property. Our initial design was to let the user set "required" as a boolean on each object property, as it's more user-friendly (that's where most people would naturally set it), but this causes a lot of implementation trickiness (how do you only let it be set on children of "object" Schema) and diverges a lot from the original spec. We compromised by removing "required" (both the array and the boolean) from the user-facing surface and providing an "optionalProperties" array on the ObjectSchema, assuming most users want most properties to be required by default, so they only have to do something actively if they want to make a property non-required.
toJSON(): Record<string, unknown> { | ||
const obj: Record<string, unknown> = {}; | ||
for (const prop in this) { | ||
if (this.hasOwnProperty(prop) && this[prop] !== undefined) { |
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 think checking if this.hasOwnProperty(prop)
is redundant in this case, since we are iterating over the properties of 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.
TS/ESlint yells about that, I think it's because classes have some built-in inherited native properties and hasOwnProperty skips them and focuses on the properties you explicitly put on it.
See https://docs.google.com/document/d/1CXRbH7zmKqupD5LWUq8dh3spsGpozfRbOUa5MWi2tVY/edit?tab=t.wiordux8zots (internal)
Rewriting Schema as a class with static methods to enable easier building and some validation.
This is mostly backwards compatible - functionDeclaration.parameters takes an ObjectSchemaInterface which could be the ObjectSchema class or just a JS object that matches the interface. The only breaking change is the FunctionDeclarationSchemaType enum is now named SchemaType.
Keeping validation minimal as (1) TS should handle a lot of it and even if TS checking doesn't extend to JS-only developers, we don't really want to duplicate efforts with TS, (2) not a lot of rules have strong enough confirmation/guarantees from the backend for us to be sure enough to throw errors.