-
Notifications
You must be signed in to change notification settings - Fork 706
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
Schema helper functions #1197
Schema helper functions #1197
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.
I'm not 100%, but parts of this look like a re-implementation of parts of lodash - worth taking a look.
expect(retrieveBasicFormParams(t.values, t.schema)).toEqual(t.result); | ||
}); | ||
}); | ||
}); |
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.
👏 Excellent clear tests!
dashboard/src/shared/schema.ts
Outdated
return basicFormParameters; | ||
} | ||
|
||
// getDocumentElem returns the YAML element given a root element |
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.
Unless I'm missing something, rootElem
here is just an object right? In which case, we can possibly remove (and not have to maintain) this function completely in favor of https://lodash.com/docs/#get ?
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, unfortunately it's not. It's a YAML.ast.Document
from https://eemeli.org/yaml/#documents so we cannot use lodash methods.
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.
Ah - I see. Thanks for the reference. So... at least for this function: lodash.get(rootElem.toJSON(), path, defaults)
?
Actually, checking the docs, it looks like YAML
provides getIn
for this reason? It takes an iterable which is the path segments, as in, if we had a document.contents AST representing { foo: { bar: [8, 9] } }
, then we should be able to use rootElem.getIn(['foo', 'bar', 1])
to get the value 9
? At least, that's what I understand from the docs... I'd be surprised if we needed to implement getValue
and setValue
ourselves.
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, nice catch, I understood that differently (I thought that the *In
methods only worked with collections/arrays) but it's true that we can use that. Thanks!
The only caveat I have found is that setIn
returns an error if the object doesn't define the parent element:
> d.toString()
'a: b\n'
> d.setIn(["b", "c"], "foo")
Error: Expected YAML collection at b. Remaining path: c
In any case, that's the same limitation that we have now.
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.
Thanks for the info - more comments in-line :)
dashboard/src/shared/schema.ts
Outdated
return basicFormParameters; | ||
} | ||
|
||
// getDocumentElem returns the YAML element given a root element |
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.
Ah - I see. Thanks for the reference. So... at least for this function: lodash.get(rootElem.toJSON(), path, defaults)
?
Actually, checking the docs, it looks like YAML
provides getIn
for this reason? It takes an iterable which is the path segments, as in, if we had a document.contents AST representing { foo: { bar: [8, 9] } }
, then we should be able to use rootElem.getIn(['foo', 'bar', 1])
to get the value 9
? At least, that's what I understand from the docs... I'd be surprised if we needed to implement getValue
and setValue
ourselves.
dashboard/src/shared/schema.ts
Outdated
defaultValues: string, | ||
schemaProperties: {}, | ||
parentPath?: string, | ||
params?: IBasicFormParam[], |
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 found this argument odd - why pass the ref to the array as an arg, rather than just relying on the function return value? You could remove this argument - I think - if you...
dashboard/src/shared/schema.ts
Outdated
schemaProperties: {}, | ||
parentPath?: string, | ||
params?: IBasicFormParam[], | ||
) { |
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.
always create a params array here, and then...
dashboard/src/shared/schema.ts
Outdated
// Use the default value either from the JSON schema or the default values | ||
value: getDefaultValue(defaultValues, itemPath) || schemaProperties[propertyKey].default, | ||
}; | ||
params = params ? params.concat(newParam) : [newParam]; |
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.
only ever params.concat(newParam)
here, then...
dashboard/src/shared/schema.ts
Outdated
} | ||
// If the property is an object, iterate recursively | ||
if (schemaProperties[propertyKey].type === "object") { | ||
params = lookForFormParams( |
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.
params.concat(lookForFormParams(...))
recursively here (but without passing in the params
arg, obviously).
Or why do you need to rely on both a return value and an array reference as a function arg?
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.
took me a while to get my head around that one 😅
You are right, the params
argument is not needed.
Apart from your feedback @absoludity I have added the types for |
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.
Sweet, that's much clearer, thanks for the updates!
Still one thing I'm unsure about - why we call setValue
with a string yaml doc and return a string, rather than just keeping a reference to the doc in the form state so that we'd pass the doc, update it, and return the same ref (or not even need to return it)?
But +1 either way.
dashboard/src/shared/schema.ts
Outdated
if (schema && schema.properties) { | ||
return lookForFormParams(defaultValues, schema.properties); | ||
} | ||
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.
This function looks like it doesn't do much now - other than verify the schema has properties... why not rename lookForFormParams
to retrieveBasicFormParams
and have call-sites use that (if they have properties)? Given that lookForPormParams
no longer has the array arg (which may have been awkward for call-sites to call with an empty array), it now looks exportable?
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.
yes, we can do that, I wanted to split it for being a bit more readable but probably there is not much difference.
const doc = YAML.parseDocument(values); | ||
const splittedPath = path.split("."); | ||
return (doc as any).getIn(splittedPath) || defaultValue; | ||
} |
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.
Great - getValue
and setValue
are much simpler now. I'm still not sure why we pass string values into these, rather than passing the actual document. I expected that the form state would be the document, which gets updated with data by the user... converting that to a string and back on each change seems superfluous, but maybe there is context I'm missing?
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.
My reasoning is that the the values.yaml
is received as a string and it's always treated as a normal string in the Form
component if it doesn't have support for the basic form.
My idea is to have this abstraction layer so the Form
always work with the string values.yaml
regardless of the implementation of this library. We are using yaml Document
s but we could be using regexps or lodash
to modify those values. That way, the Form
component doesn't depend on the implementation details here.
Also, if we maintain in the Form
state the Document
we would need to implement there the transformation string
<-->Document
.
Follow up #1196
Actual implementation of the
schema
helper function. There are two main functions:An issue to mention is that the
yaml
package doesn't support Typescript definitions (yet), the current package has some missing definitions and it's not usable so we need to work with plan javascript.