feat: allow config file to have config globs - #129
Conversation
metalwarrior665
left a comment
There was a problem hiding this comment.
This looks simpler than I thought :) I have just minor remarks, feel free to argue against them. Let's wait for Juan but this seems quite uncontroversial.
| for (const [index, configEntry] of configs.entries()) { | ||
| const { folder, actorFullName } = configEntry as ActorGlobConfigEntry; | ||
|
|
||
| // TODO: Allow for combined filtering? |
There was a problem hiding this comment.
I would allow this, don't think it is that confusing or dangerous. You simply filter once per folder and then per name. There might be legit use-cases for this
| import { selectActors } from './actor-filtering.js'; | ||
| import { isPathWithinScope } from './path-utils.js'; | ||
| import type { ActorConfig, ActorConfigFile } from './types.js'; | ||
| import type { ActorConfig, ActorConfigFile, ActorConfigFileEntry, ActorGlobConfigEntry } from './types.js'; |
There was a problem hiding this comment.
These types don't match very well, one says "File", other doesn't.
btw we already have ActorConfig type which is basically the same thing, we should either unify them or derive one from the other. Are there cases where these will differ? If we are simply merging them then they should not differ. No need to solve that in this PR but sooner rather than later.
|
|
||
| const validateGlobConfigEntries = (configs: unknown[]): ActorGlobConfigEntry[] => { | ||
| for (const [index, configEntry] of configs.entries()) { | ||
| const { folder, actorFullName } = configEntry as ActorGlobConfigEntry; |
There was a problem hiding this comment.
Could be zod parse I guess but I don't know if you can get such a nice errors from it, don't have experience
|
|
||
| let overlay: Partial<ActorConfigFileEntry> = {}; | ||
| for (const configEntry of [...matchingFolderConfigs, ...matchingActorFullNameConfigs]) { | ||
| const { folder: matchedFolder, actorFullName: matchedActorFullName, ...rest } = configEntry; |
There was a problem hiding this comment.
Let's think a bit if we shouldn't separate the matching fields folder, actorFullName vs the configs, it is a bit weird they are on the same level
| ); | ||
|
|
||
| let overlay: Partial<ActorConfigFileEntry> = {}; | ||
| for (const configEntry of [...matchingFolderConfigs, ...matchingActorFullNameConfigs]) { |
There was a problem hiding this comment.
If we want to support having both folder and name with AND logic, this would need to change
| const matchingActorFullNameConfigs = configs.filter( | ||
| (configEntry) => | ||
| configEntry.actorFullName !== undefined && | ||
| typeof actorEntry.actorFullName === 'string' && |
There was a problem hiding this comment.
We already validate this eariler and the type should be string | undefined now, no?
Closes #128
configs?: ActorGlobConfigEntry[]on the config file. Each entry has exactly one offolder/actorFullName(a glob pattern, matched viaminimatch) plus whatever fields to overlay onto matching actors.mergeGlobConfigs) is field-agnostic — it overlays whatever properties a matching entry carries besides its match key, with no special knowledge oftokenEnvVaror any other field name. An unrecognized/misspelled property is merged in and simply has no effect, same as today.folder-glob entries → matchingactorFullName-glob entries → the actor's own literal entry (never overridden). Within the same glob type, the last matching entry in the array wins — purely by array position, not by pattern specificity.minimatchglob rules, see https://github.com/isaacs/minimatch for the full pattern syntax. Notably, "match every actor" needs**, not*, since*doesn't cross path segments.tokenEnvVaris optional on an actor entry now, but still required overall: once an actor's full config is resolved (literal + any matchingconfigs), atokenEnvVarmust be present orreadConfigFilethrows — this is the only place the code cares about that specific field name.configsis entirely optional; a config file without it behaves exactly as before.