c12 icon indicating copy to clipboard operation
c12 copied to clipboard

fix: overwrite defaults instead of merging them

Open kevinwolfcr opened this issue 1 year ago • 4 comments

In my opinion (maybe I am wrong) the defaults should act as a fallback for when a given property is not specified, rather than being merged with it.

The problem

For the following script:

import { loadConfig } from "c12"

export type MyConfig = {
  prop1: string[]
  prop2: string[]
}

async function loadMyConfig() {
  const { config } = await loadConfig<MyConfig>({
    defaults: {
      prop1: ["1", "2"],
      prop2: ["3", "4"],
    },
  })

  console.log(config)
}

loadMyConfig()

And the following config:

export default {
  prop1: ["a", "b"],
  prop2: ["c", "d"],
}

I was expecting to receive this:

{
  "prop1": [ "a", "b" ],
  "prop2": [ "c", "d" ]
}

But instead received this

{
  "prop1": [ "a", "b", "1", "2" ],
  "prop2": [ "c", "d", "3", "4" ]
}

The solution

Instead of merging both the accumulated config with the defaults, I am spreading the accumulated config over the defaults. This way, default properties will keep untouched if they are not present in the accumulated config.

kevinwolfcr avatar Sep 16 '22 18:09 kevinwolfcr

Thanks for the PR @fullstackjedi. I can understand it is desired by your use case to replace array when applying defaults but it is not an easy change because this strategy with defu is widely adopted. What we can do, is supporting a custom merging strategy as merge: (obj, defaults) (c12 option) to replace defu.

pi0 avatar Sep 19 '22 10:09 pi0

I understand, so as of now, there is no way to overwrite a JS object (array or map)? I also agree that the ability to change the merging strategy could work.

I also have a question, what is the main difference or when I can use defaultConfig vs defaults?

kevinwolfcr avatar Sep 19 '22 16:09 kevinwolfcr

Adding an option would be nice 👍

Different between defaults and defaultConfig is slight.

Normally you would eant to use defaults as it gets applied with least periority. Their difference is whan you are using extends feature. First defaultConfig is applied before extends happening therefor has periority over extends layers. This was useful for unjs/nitro extends. (PR welcome if you like to improve description of them in docs?

pi0 avatar Sep 19 '22 16:09 pi0

Adding an option would be nice 👍

Different between defaults and defaultConfig is slight.

Normally you would eant to use defaults as it gets applied with least periority. Their difference is whan you are using extends feature. First defaultConfig is applied before extends happening therefor has periority over extends layers. This was useful for unjs/nitro extends. (PR welcome if you like to improve description of them in docs)

pi0 avatar Sep 19 '22 16:09 pi0