-
Notifications
You must be signed in to change notification settings - Fork 478
[configure-splash-screen] Refactor and integrate with @expo/config
#2297
[configure-splash-screen] Refactor and integrate with @expo/config
#2297
Conversation
/** | ||
* This class is responsible for validating configuration object in a form of json and produce validated object based on validating `rules` added via `addRule` method. | ||
*/ | ||
export default class FromJsonValidator<From extends JsonShape<To>, To extends 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 class is pretty clever. we should probably pull it out into a util. out of curiosity, did you consider any other npm packages to do a similar thing? i'm not familiar with any that both transform and validate like this does
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.
Congratulations on implementing an object validator! I too am curious whether you considered other NPM packages. As I mentioned on one of the calls I've had pretty good experience with zod
which, I guess, does the same thing (parses an unknown object into an object of a known TS type, inferring and parsing types and optionally validates)?
While I admire the heart you've put into this and stuff you must have learned along the way I'm a little afraid maintaining this may be a burden no one will want to take a couple of months from now and this will become a zombie file here be dragons.
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.
Well, it was my little experiment 😉
I really like the zod
idea and I'm willing to add it to our codebase somewhere. I'm not sure though if zod
can provide validation & transformation at the same time, please take a look at following lines:
https://github.com/expo/expo-cli/pull/2297/files#diff-63c94c9e1d2966b124e8333ec934d795R55
https://github.com/expo/expo-cli/pull/2297/files#diff-63c94c9e1d2966b124e8333ec934d795R29
These represent the same think, but one in JSON and other in it's semantically-validated equivalent (Color
is a tuple). What I'm curious about is: whether zod
can convert for example string into some complex object/structure? 🤔 Nonetheless, IMO it's still worth to be added 👍
packages/configure-splash-screen/src/validators/__tests__/android.test.ts
Show resolved
Hide resolved
I think the current structure of this code lends itself very well to testing. If we test the validator/transformer functions exhaustively, then we can do some e2e tests that ensure they're wired up correctly with the CLI/external api. One thing that we might want to do is split out the FromJsonValidator and test that independently, then just assume it works as it promises though its API within this code. We can do that in a followup PR. |
packages/configure-splash-screen/src/__tests__/cli-command.test.ts
Outdated
Show resolved
Hide resolved
packages/configure-splash-screen/src/android/__tests__/Colors.xml.test.ts
Outdated
Show resolved
Hide resolved
Linking with #1494 |
Oooh… thanks for reminding to review 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.
This is a very clever pull request (which means both good and bad). 😅 Had some questions, apart from them it looks very solid!
/** | ||
* This class is responsible for validating configuration object in a form of json and produce validated object based on validating `rules` added via `addRule` method. | ||
*/ | ||
export default class FromJsonValidator<From extends JsonShape<To>, To extends 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.
Congratulations on implementing an object validator! I too am curious whether you considered other NPM packages. As I mentioned on one of the calls I've had pretty good experience with zod
which, I guess, does the same thing (parses an unknown object into an object of a known TS type, inferring and parsing types and optionally validates)?
While I admire the heart you've put into this and stuff you must have learned along the way I'm a little afraid maintaining this may be a burden no one will want to take a couple of months from now and this will become a zombie file here be dragons.
const AVAILABLE_OPTIONS_NAMES = [ | ||
'imageResizeMode', | ||
'platform', | ||
'backgroundColor', | ||
'imagePath', | ||
'darkModeBackgroundColor', | ||
'darkModeImagePath', | ||
'statusBarHidden', | ||
'statusBarStyle', | ||
'darkModeStatusBarStyle', | ||
'statusBarTranslucent', | ||
'statusBarBackgroundColor', | ||
'darkModeStatusBarBackgroundColor', | ||
] as const; | ||
|
||
type CLIOptionName = typeof AVAILABLE_OPTIONS_NAMES[number]; |
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 this sophisticated const AVAILABLE_OPTIONS_NAMES
and then this typeof
instead of a simple enum or a union type?
|
||
type CLIOptionName = typeof AVAILABLE_OPTIONS_NAMES[number]; | ||
|
||
type CLIOptions = Partial<Record<CLIOptionName, string>>; |
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.
Wouldn't type of statusBarTranslucent
be boolean
?
if (!backgroundColor) { | ||
throw new Error( | ||
`'backgroundColor': Required option is not provided. Provide a valid color string.` | ||
); | ||
} |
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 recent releases of commander.js
allow usage of requiredOption
if that's something we may want to look into
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, it does, but I couldn't get this option covered by tests then 😞 Commander.js simply kills the process with exit code 1
once the option is not provided. Maybe it does not need to be tested then? 🤔 Dunno 🤷
} | ||
|
||
const resolvedStatusBarHidden = | ||
statusBarHidden === undefined ? undefined : Boolean(statusBarHidden); |
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.
Passing undefined
in a variable called resolved
seems icky to me. Is there a specific reason for passing undefined
down? Does it say "do not modify anything related to this setting"?
Actually while writing this comment I had deja vu, so if we already talked about this then sorry
…ig types - created generic SplashScreenConfig type - created platform-specific SplashScreenConfig types - created JSON-friendly equivalent of above-mentioned types - created mapping type for modyfing arbitrary type with new subschema - created mapping type for generatig JSON-friendly type equivalent from given type
…ith new bin and main entries
41680ca
to
755420d
Compare
@@ -0,0 +1,138 @@ | |||
import configureAndroid from '../android'; |
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 should rename all of these tests to -test
after this PR is merged. #2591
|
@bbarthec @EvanBacon - let's chat at the next expo-cli meeting about which xml library we should be using, we currently have three (that i'm aware of? maybe more?):
we need to consolidate on one to reduce duplicate dependencies and ensure that we're not reformatting the xml files in subtle ways when different commands are executed. |
Do you guys have any major concerns about this PR apart from the |
Why
@expo/config
should autoconfigure the splash screen onceexpo eject
is called instead of showing nasty warning.How
This whole PR is much too big and complex to be called
a nice one
😅The amount of code that has been written is not even to be compared to the amount of functionality this PR provides (to the disadvantage of the the first).
Nevertheless I've decided to try to ship it in the shape it is.
Why? Because I've experimented with:
SplashScreenConfig
typeSplashScreenConfig
types that are created dynamically viamapped type
@expo/config
) and are dynamically generated from original types via othermapped type
Validator
object that has this nicely lookingaddRule
method that is fully TS-supportedcli
command separated completely from logic now (only defines CLI options and performs minimal validation and shaping raw JSON Config for further processing)