refactor(readConfigFile): rework config file reading and testing - #139
Conversation
ruocco-l
left a comment
There was a problem hiding this comment.
Just some questions, but looks ok to me, thanks!
| * Stage 3 — normalizes the paths the user wrote and rejects entries that collide once normalized. | ||
| * The repo root is "" from here on, however it was spelled in the file. | ||
| */ | ||
| export const denormalizeConfig = (config: ActorConfigFile): DenormalizedActor[] => { |
There was a problem hiding this comment.
Why is it called denormalize if it normalizes (according to the JSDoc)?
There was a problem hiding this comment.
it normalizes the paths but the action as a whole is denormalizing (tbh i didn't read the jsdoc my bad my bad).
Will fix it
| const seenFolders = new Set<string>(); | ||
|
|
||
| return config.actors.map((entry) => { | ||
| const folder = entry.folder === '.' ? '' : stripTrailingSlash(entry.folder); |
There was a problem hiding this comment.
I know that this was already here, but i realized that you can trick this by using "./" in the config file. Can you fix it now, since we are touching on it?
There was a problem hiding this comment.
i'll fix it in the path resolution pr (PR number 3)
Since there is quite a bit of dubious stuff around paths
| }); | ||
| }; | ||
|
|
||
| it('loadActorConfig resolves an entry that never came from a config file', async () => { |
There was a problem hiding this comment.
I don't understand what this is supposed to mean
There was a problem hiding this comment.
me neither, fixed
metalwarrior665
left a comment
There was a problem hiding this comment.
The flow is nice, seems like something we could stick to long term. Just few polishing suggestions.
| * trace left of which config flavour produced it. Whatever replaces or extends | ||
| * {@link parseConfigFile} only has to produce this. | ||
| */ | ||
| export interface DenormalizedActor { |
There was a problem hiding this comment.
- I think the naming will need some work. One is Actor and other is ActorConfig, so shouldn't this be
DenormalizedActorConfig? - Do we need this ugly term? We could also do something like
ActorConfigBase->ActorConfigComplete(or similar)? Or perhapsActorConfigWithSchemasas that is what it does for now
There was a problem hiding this comment.
- true
- i mean it is the right term. Maybe
ResolvedActorConfig?
|
|
||
| // The repo root is spelled "" internally but "." in a config file, so report it the way a reader | ||
| // would have written it. | ||
| const displayFolder = (folder: string): string => folder || '.'; |
There was a problem hiding this comment.
I would inline this or at least define it closer to where used.
| // would have written it. | ||
| const displayFolder = (folder: string): string => folder || '.'; | ||
|
|
||
| type ConfigIssue = z.ZodError<ActorConfigFile>['issues'][number]; |
There was a problem hiding this comment.
Is issue an official term? I would think more about validationError or at least validationIssue
There was a problem hiding this comment.
set to ConfigParsingIssue since its parsing* not validation whats going on
|
|
||
| switch (file.reason) { | ||
| case 'invalid-json': | ||
| throw new Error(`Config file "${CONFIG_FILE_NAME}" contains invalid JSON.`); |
There was a problem hiding this comment.
Add a comment we might want to support jsonc in the future
| */ | ||
| export async function safeReadJsonObjectFile(path: string): Promise<JsonObjectReadResult> { | ||
| // `stat`, not `lstat`: a symlink must resolve to its target, matching what `readFile` does below. | ||
| const stats = await stat(path).catch(() => null); |
There was a problem hiding this comment.
Let's use sync IO, so we don't have to propagate async everywhere. From outside async looks like we will do some network calls.
This is a sequential step in CLI, we don't need wide concurrency like a web server.
There was a problem hiding this comment.
YES!!! i did not touch it due to chesterton's fence. but it bugged me the whole time
| // replace these two when enabling different file structures | ||
| // some kind of strategy pattern seems appropriate here | ||
| const parsedConfigFile = parseConfigFile(rawConfigFile); | ||
| const entries = denormalizeConfig(parsedConfigFile); |
There was a problem hiding this comment.
Again the variables don't follow. parsedConfigFile -> entries -> actorConfigs. They should derive from one another.
| @@ -0,0 +1,57 @@ | |||
| import { readFile, stat } from 'node:fs/promises'; | |||
There was a problem hiding this comment.
files.ts is too generic. How about json-object.ts. We can make more files for other things later
| @@ -0,0 +1,251 @@ | |||
| import path from 'node:path'; | |||
There was a problem hiding this comment.
Instead of having a utils dump, we could just have bin/config-parsers/. We will also add the actor.json parsing to it is already 3 related files.
There was a problem hiding this comment.
i was about to do this now since i started doing groundwork for the multiple config structures and noticed it as an issue.
Will solve it here.
| // Strips a trailing slash so config-declared paths ("actors/shopify/" vs "actors/shopify") compare equal. | ||
| const stripTrailingSlash = (pathValue: string): string => pathValue.replace(/\/+$/, ''); | ||
|
|
||
| const findOverlappingContextPaths = (contextPaths: string[]): [string, string] | undefined => { |
There was a problem hiding this comment.
Next time it would be good to add PR comment that this function was moved as is so I don't have to read it. Not sure if there is some easy hack for me to do this...
There was a problem hiding this comment.
sometimes github detects it, but its really hit or miss
PR number one of the setup for config file reworks.
Featuring:
readConfigFilepassing previous mock-based test battery and new fixture-based one