@adamhl8/configs 1.6.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,6 +6,21 @@ Configs (`tsconfig`, `oxfmt`, `oxlint`, etc.) I use across my projects.
6
6
  bun add -D @adamhl8/configs
7
7
  ```
8
8
 
9
+ ### Config merging
10
+
11
+ Each `fooConfig({ ... })` function deep merges your config into the base config. Arrays are appended to the base array by default. To control this per key, any array-typed key can instead take `{ value: [...], mode: "merge" | "replace" }`:
12
+
13
+ ```ts
14
+ const config = oxlintConfig({
15
+ // appended to the base plugins (same as passing a plain array)
16
+ plugins: { value: ["my-plugin"], mode: "merge" },
17
+ // used as-is, the base overrides are dropped
18
+ overrides: { value: [], mode: "replace" },
19
+ })
20
+ ```
21
+
22
+ The wrapper works at any depth and never appears in the merged result, in the types or at runtime.
23
+
9
24
  ### just
10
25
 
11
26
  Scripts live in a shared [`just`](https://github.com/casey/just) base justfile instead of being copied into every project's `package.json`. Your `justfile`:
@@ -3,8 +3,6 @@ set unstable
3
3
  set default-list
4
4
  set allow-duplicate-recipes
5
5
 
6
- export PATH := justfile_directory() + "/node_modules/.bin:" + env("PATH")
7
-
8
6
  # runs cmd if the condition command succeeds, echoing cmd only when it runs
9
7
  run-when(cmd, condition) := f"if {{condition}}; then echo {{style("command", cmd)}}; {{cmd}}; fi"
10
8
 
@@ -17,9 +15,9 @@ tofu-run-condition := '[ -z "${CI:-}" ] && ls *.tofu >/dev/null 2>&1 && aws conf
17
15
  prepare: _prepare
18
16
  _prepare:
19
17
  lefthook install
20
- adamhl8-gitignore
21
- adamhl8-bunfig
22
- oxfmt bunfig.toml
18
+ bun adamhl8-gitignore
19
+ bun adamhl8-bunfig
20
+ bun oxfmt bunfig.toml
23
21
  @{{ run-when("tofu init -upgrade", tofu-run-condition) }}
24
22
 
25
23
  bump-deps: _bump-deps
@@ -35,15 +33,15 @@ _tofu-check:
35
33
 
36
34
  lint: _lint
37
35
  _lint:
38
- markdown-toc -i --bullets '-' --maxdepth 3 ./README.md
39
- oxlint --fix --fix-suggestions --fix-dangerously
40
- oxfmt
41
- knip-bun
36
+ bun markdown-toc -i --bullets '-' --maxdepth 3 ./README.md
37
+ bun oxlint --fix --fix-suggestions --fix-dangerously
38
+ bun oxfmt
39
+ bun knip-bun
42
40
  @just test
43
41
 
44
42
  build: _build
45
43
  _build: lint && tofu-check
46
- @{{ run-when("tsdown", "[ -f tsdown.config.ts ]") }}
44
+ @{{ run-when("bun tsdown", "[ -f tsdown.config.ts ]") }}
47
45
 
48
46
  test: _test
49
47
  _test:
@@ -57,4 +55,4 @@ _release:
57
55
  release-run: _release-run
58
56
 
59
57
  _release-run:
60
- release-it -VV --ci -i "$(adamhl8-cliff --bumped-version)"
58
+ bun release-it -VV --ci -i "$(adamhl8-cliff --bumped-version)"
@@ -1 +1 @@
1
- {"version":3,"file":"knip.base.d.ts","names":[],"sources":["../../src/configs/knip.base.ts"],"mappings":";;;cAuBa,YAAU,sBAAA;;;;;aAJnB"}
1
+ {"version":3,"file":"knip.base.d.ts","names":[],"sources":["../../src/configs/knip.base.ts"],"mappings":";;;cAsBa,YAAU,sBAAA;;;;;aAJnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"knip.base.js","names":[],"sources":["../../src/configs/knip.base.ts"],"sourcesContent":["import type { KnipConfig } from \"knip\"\n\nimport { createMergeConfigFn } from \"#utils.ts\"\n\n/** Knip sees `just` in the `prepare` script and the release-it hooks, but it isn't a package.json dependency */\nconst IGNORE_BINARIES = [\"just\"] as const satisfies string[]\n\n/**\n * - Knip resolves `@adamhl8/eslint-plugin-clean-modules` via the oxlint config, but we don't need to install it directly\n * in the consuming project, so it shows as unlisted\n */\nconst IGNORE_DEPENDENCIES = [\"@adamhl8/eslint-plugin-clean-modules\"] as const satisfies string[]\n\nconst baseConfig = {\n project: [\"**/*\"],\n // entry: [\"**/*.test.ts\"],\n ignoreBinaries: IGNORE_BINARIES,\n ignoreDependencies: IGNORE_DEPENDENCIES,\n bun: {\n entry: [\"**/*.test.ts\"],\n },\n} as const satisfies KnipConfig\n\nexport const knipConfig = createMergeConfigFn<KnipConfig, typeof baseConfig>(baseConfig)\n"],"mappings":";AAuBA,MAAa,aAAa,oBAAmD;CAT3E,SAAS,CAAC,MAAM;CAEhB,gBAAgB,CAXO,MAWO;CAC9B,oBAAoB,CANO,sCAMW;CACtC,KAAK,EACH,OAAO,CAAC,cAAc,EACxB;AAG2E,CAAU"}
1
+ {"version":3,"file":"knip.base.js","names":[],"sources":["../../src/configs/knip.base.ts"],"sourcesContent":["import type { KnipConfig } from \"knip\"\n\nimport { createMergeConfigFn } from \"#utils.ts\"\n\n/** Knip sees `just` in the `prepare` script and the release-it hooks, but it isn't a package.json dependency */\nconst IGNORE_BINARIES = [\"just\"] as const satisfies string[]\n\n/**\n * - Knip resolves `@adamhl8/eslint-plugin-clean-modules` via the oxlint config, but we don't need to install it directly\n * in the consuming project, so it shows as unlisted\n */\nconst IGNORE_DEPENDENCIES = [\"@adamhl8/eslint-plugin-clean-modules\"] as const satisfies string[]\n\nconst baseConfig = {\n project: [\"**/*\"],\n ignoreBinaries: IGNORE_BINARIES,\n ignoreDependencies: IGNORE_DEPENDENCIES,\n bun: {\n entry: [\"**/*.test.ts\"],\n },\n} as const satisfies KnipConfig\n\nexport const knipConfig = createMergeConfigFn<KnipConfig, typeof baseConfig>(baseConfig)\n"],"mappings":";AAsBA,MAAa,aAAa,oBAAmD;CAR3E,SAAS,CAAC,MAAM;CAChB,gBAAgB,CAVO,MAUO;CAC9B,oBAAoB,CALO,sCAKW;CACtC,KAAK,EACH,OAAO,CAAC,cAAc,EACxB;AAG2E,CAAU"}
@@ -1,8 +1,8 @@
1
- import { MergeConfigFn, OptionalMergeConfigFn } from "../utils.js";
1
+ import { MergeConfigFn } from "../utils.js";
2
2
  import { SetRequired } from "type-fest";
3
3
  import { UserConfig } from "tsdown";
4
4
  //#region src/configs/tsdown.base.d.ts
5
- type StrictUserConfig = SetRequired<UserConfig, "platform">;
5
+ type StrictConfig = SetRequired<UserConfig, "platform">;
6
6
  declare const baseConfig: {
7
7
  readonly entry: ["./src/index.ts"];
8
8
  readonly platform: "neutral";
@@ -27,8 +27,8 @@ declare const baseConfig: {
27
27
  readonly publint: true;
28
28
  readonly failOnWarn: true;
29
29
  };
30
+ type StrictBundleConfig = SetRequired<UserConfig, "platform" | "entry">;
30
31
  declare const bundleConfig: {
31
- readonly entry: ["./src/index.ts"];
32
32
  readonly platform: "neutral";
33
33
  readonly target: false;
34
34
  readonly minify: "dce-only";
@@ -38,6 +38,7 @@ declare const bundleConfig: {
38
38
  readonly neverBundle: ["bun"];
39
39
  };
40
40
  readonly failOnWarn: true;
41
+ readonly entry: [];
41
42
  readonly unbundle: false;
42
43
  readonly sourcemap: false;
43
44
  readonly dts: false;
@@ -49,9 +50,8 @@ declare const bundleConfig: {
49
50
  };
50
51
  };
51
52
  };
52
- declare const tsdownConfig: MergeConfigFn<StrictUserConfig, typeof baseConfig>;
53
- declare const tsdownBundleConfig: MergeConfigFn<StrictUserConfig, typeof bundleConfig>;
54
- declare const tsdownBinConfig: OptionalMergeConfigFn<UserConfig, {
53
+ type StrictBinConfig = SetRequired<UserConfig, "entry">;
54
+ declare const binConfig: {
55
55
  readonly target: false;
56
56
  readonly minify: "dce-only";
57
57
  readonly fixedExtension: false;
@@ -60,6 +60,7 @@ declare const tsdownBinConfig: OptionalMergeConfigFn<UserConfig, {
60
60
  readonly neverBundle: ["bun"];
61
61
  };
62
62
  readonly failOnWarn: true;
63
+ readonly entry: [];
63
64
  readonly unbundle: false;
64
65
  readonly sourcemap: false;
65
66
  readonly dts: false;
@@ -70,12 +71,14 @@ declare const tsdownBinConfig: OptionalMergeConfigFn<UserConfig, {
70
71
  readonly attachDebugInfo: "none";
71
72
  };
72
73
  };
73
- readonly entry: [];
74
74
  readonly platform: "node";
75
75
  readonly outExtensions: () => {
76
76
  readonly js: "";
77
77
  };
78
- }>;
78
+ };
79
+ declare const tsdownConfig: MergeConfigFn<StrictConfig, typeof baseConfig>;
80
+ declare const tsdownBundleConfig: MergeConfigFn<StrictBundleConfig, typeof bundleConfig>;
81
+ declare const tsdownBinConfig: MergeConfigFn<StrictBinConfig, typeof binConfig>;
79
82
  //#endregion
80
83
  export { tsdownBinConfig, tsdownBundleConfig, tsdownConfig };
81
84
  //# sourceMappingURL=tsdown.base.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tsdown.base.d.ts","names":[],"sources":["../../src/configs/tsdown.base.ts"],"mappings":";;;;KAOK,mBAAmB,YAAY;cAE9B;;;;;;;;;;aAUF;aACA;aACA;;;aAGA;;;aAGA;aACA;;;;;cAOE;;;;;;;;aAXF;;;;;;;;;aAmBA;eACE;;;;cAcO,cAAc,cAAc,yBAAyB;cAKrD,oBAAoB,cAAc,yBAAyB;cAK3D,iBAAe,sBAAA;;;;;;aA5CxB;;;;;;;;;aAmBA;eACE"}
1
+ {"version":3,"file":"tsdown.base.d.ts","names":[],"sources":["../../src/configs/tsdown.base.ts"],"mappings":";;;;KAOK,eAAe,YAAY;cAE1B;;;;;;;;;;aAUF;aACA;aACA;;;aAGA;;;aAGA;aACA;;;;;KAOC,qBAAqB,YAAY;cAGhC;;;;;;;aAdF;;;;;;;;;;aAuBA;eACE;;;;KAMD,kBAAkB,YAAY;cAG7B;;;;;;aAjCF;;;;;;;;;;aAuBA;eACE;;;;;;;;cAeO,cAAc,cAAc,qBAAqB;cAKjD,oBAAoB,cAAc,2BAA2B;cAK7D,iBAAiB,cAAc,wBAAwB"}
@@ -24,6 +24,7 @@ const baseConfig = {
24
24
  };
25
25
  const bundleConfig = {
26
26
  ...baseConfig,
27
+ entry: [],
27
28
  unbundle: false,
28
29
  sourcemap: false,
29
30
  dts: false,
@@ -33,7 +34,6 @@ const bundleConfig = {
33
34
  };
34
35
  const binConfig = {
35
36
  ...bundleConfig,
36
- entry: [],
37
37
  platform: "node",
38
38
  outExtensions: () => ({ js: "" })
39
39
  };
@@ -1 +1 @@
1
- {"version":3,"file":"tsdown.base.js","names":[],"sources":["../../src/configs/tsdown.base.ts"],"sourcesContent":["import type { UserConfig } from \"tsdown\"\nimport type { SetRequired } from \"type-fest\"\n\nimport type { MergeConfigFn } from \"#utils.ts\"\nimport { createMergeConfigFn } from \"#utils.ts\"\n\n// Force projects to specify platform\ntype StrictUserConfig = SetRequired<UserConfig, \"platform\">\n\nconst baseConfig = {\n entry: [\"./src/index.ts\"],\n platform: \"neutral\",\n target: false,\n unbundle: true,\n sourcemap: true,\n minify: \"dce-only\",\n fixedExtension: false,\n hash: false,\n dts: {\n newContext: true,\n tsgo: true,\n sourcemap: true,\n },\n deps: {\n neverBundle: [\"bun\"],\n },\n attw: {\n level: \"error\",\n profile: \"esm-only\",\n },\n publint: true,\n failOnWarn: true,\n} as const satisfies StrictUserConfig\n\n// Single-file bundle (not a published library): bundle everything, drop types/lint/sourcemap.\nconst bundleConfig = {\n ...baseConfig,\n unbundle: false,\n sourcemap: false,\n dts: false,\n attw: false,\n publint: false,\n inputOptions: {\n experimental: {\n attachDebugInfo: \"none\", // remove region comments from bundled output\n },\n },\n} as const satisfies StrictUserConfig\n\n// A bin is a node bundle with no output file extension.\nconst binConfig = {\n ...bundleConfig,\n entry: [],\n platform: \"node\",\n outExtensions: () => ({ js: \"\" }) as const,\n} as const satisfies UserConfig\n\n// Annotated as the non-optional MergeConfigFn so projects must pass a config (platform is required)\nexport const tsdownConfig: MergeConfigFn<StrictUserConfig, typeof baseConfig> = createMergeConfigFn<\n StrictUserConfig,\n typeof baseConfig\n>(baseConfig)\n\nexport const tsdownBundleConfig: MergeConfigFn<StrictUserConfig, typeof bundleConfig> = createMergeConfigFn<\n StrictUserConfig,\n typeof bundleConfig\n>(bundleConfig)\n\nexport const tsdownBinConfig = createMergeConfigFn<UserConfig, typeof binConfig>(binConfig)\n"],"mappings":";;AASA,MAAM,aAAa;CACjB,OAAO,CAAC,gBAAgB;CACxB,UAAU;CACV,QAAQ;CACR,UAAU;CACV,WAAW;CACX,QAAQ;CACR,gBAAgB;CAChB,MAAM;CACN,KAAK;EACH,YAAY;EACZ,MAAM;EACN,WAAW;CACb;CACA,MAAM,EACJ,aAAa,CAAC,KAAK,EACrB;CACA,MAAM;EACJ,OAAO;EACP,SAAS;CACX;CACA,SAAS;CACT,YAAY;AACd;AAGA,MAAM,eAAe;CACnB,GAAG;CACH,UAAU;CACV,WAAW;CACX,KAAK;CACL,MAAM;CACN,SAAS;CACT,cAAc,EACZ,cAAc,EACZ,iBAAiB,OACnB,EACF;AACF;AAGA,MAAM,YAAY;CAChB,GAAG;CACH,OAAO,CAAC;CACR,UAAU;CACV,sBAAsB,EAAE,IAAI,GAAG;AACjC;AAGA,MAAa,eAAmE,oBAG9E,UAAU;AAEZ,MAAa,qBAA2E,oBAGtF,YAAY;AAEd,MAAa,kBAAkB,oBAAkD,SAAS"}
1
+ {"version":3,"file":"tsdown.base.js","names":[],"sources":["../../src/configs/tsdown.base.ts"],"sourcesContent":["import type { UserConfig } from \"tsdown\"\nimport type { SetRequired } from \"type-fest\"\n\nimport type { MergeConfigFn } from \"#utils.ts\"\nimport { createMergeConfigFn } from \"#utils.ts\"\n\n// Force projects to specify platform\ntype StrictConfig = SetRequired<UserConfig, \"platform\">\n\nconst baseConfig = {\n entry: [\"./src/index.ts\"],\n platform: \"neutral\",\n target: false,\n unbundle: true,\n sourcemap: true,\n minify: \"dce-only\",\n fixedExtension: false,\n hash: false,\n dts: {\n newContext: true,\n tsgo: true,\n sourcemap: true,\n },\n deps: {\n neverBundle: [\"bun\"],\n },\n attw: {\n level: \"error\",\n profile: \"esm-only\",\n },\n publint: true,\n failOnWarn: true,\n} as const satisfies StrictConfig\n\n// Force projects to specify platform and entry\ntype StrictBundleConfig = SetRequired<UserConfig, \"platform\" | \"entry\">\n\n// Single-file bundle (not a published library): bundle everything, drop types/lint/sourcemap.\nconst bundleConfig = {\n ...baseConfig,\n entry: [],\n unbundle: false,\n sourcemap: false,\n dts: false,\n attw: false,\n publint: false,\n inputOptions: {\n experimental: {\n attachDebugInfo: \"none\", // remove region comments from bundled output\n },\n },\n} as const satisfies StrictBundleConfig\n\n// Force projects to specify platform and entry\ntype StrictBinConfig = SetRequired<UserConfig, \"entry\">\n\n// A bin is a node bundle with no output file extension.\nconst binConfig = {\n ...bundleConfig,\n platform: \"node\",\n outExtensions: () => ({ js: \"\" }) as const,\n} as const satisfies StrictBinConfig\n\nexport const tsdownConfig: MergeConfigFn<StrictConfig, typeof baseConfig> = createMergeConfigFn<\n StrictConfig,\n typeof baseConfig\n>(baseConfig)\n\nexport const tsdownBundleConfig: MergeConfigFn<StrictBundleConfig, typeof bundleConfig> = createMergeConfigFn<\n StrictBundleConfig,\n typeof bundleConfig\n>(bundleConfig)\n\nexport const tsdownBinConfig: MergeConfigFn<StrictBinConfig, typeof binConfig> = createMergeConfigFn<\n StrictBinConfig,\n typeof binConfig\n>(binConfig)\n"],"mappings":";;AASA,MAAM,aAAa;CACjB,OAAO,CAAC,gBAAgB;CACxB,UAAU;CACV,QAAQ;CACR,UAAU;CACV,WAAW;CACX,QAAQ;CACR,gBAAgB;CAChB,MAAM;CACN,KAAK;EACH,YAAY;EACZ,MAAM;EACN,WAAW;CACb;CACA,MAAM,EACJ,aAAa,CAAC,KAAK,EACrB;CACA,MAAM;EACJ,OAAO;EACP,SAAS;CACX;CACA,SAAS;CACT,YAAY;AACd;AAMA,MAAM,eAAe;CACnB,GAAG;CACH,OAAO,CAAC;CACR,UAAU;CACV,WAAW;CACX,KAAK;CACL,MAAM;CACN,SAAS;CACT,cAAc,EACZ,cAAc,EACZ,iBAAiB,OACnB,EACF;AACF;AAMA,MAAM,YAAY;CAChB,GAAG;CACH,UAAU;CACV,sBAAsB,EAAE,IAAI,GAAG;AACjC;AAEA,MAAa,eAA+D,oBAG1E,UAAU;AAEZ,MAAa,qBAA6E,oBAGxF,YAAY;AAEd,MAAa,kBAAoE,oBAG/E,SAAS"}
package/dist/utils.d.ts CHANGED
@@ -1,37 +1,79 @@
1
1
  import { MergeDeep, ReadonlyDeep, SimplifyDeep, WritableDeep } from "type-fest";
2
2
  //#region src/utils.d.ts
3
+ type AnyFunction = (...args: never[]) => unknown;
4
+ /**
5
+ * How a wrapped user array is combined with the base array. - `"merge"` (the default for plain arrays): the user array
6
+ * is appended to the base array - `"replace"`: the user array is used as-is
7
+ */
8
+ type ArrayMergeMode = "merge" | "replace";
9
+ /**
10
+ * A per-key array override. Wherever a config key takes an array, `{ value: [...], mode: "merge" | "replace" }` may be
11
+ * passed instead; `mode` controls how that key's array combines with the base config's. The wrapper never appears in
12
+ * the merged result. A config value that is exactly this shape is always consumed as a wrapper; an object with extra
13
+ * keys is treated as a plain config object.
14
+ */
15
+ interface ArrayOverride<Value extends readonly unknown[], Mode extends ArrayMergeMode = ArrayMergeMode> {
16
+ readonly value: Value;
17
+ readonly mode: Mode;
18
+ }
19
+ /** True only when T is exactly the wrapper shape (keys value + mode, nothing else), mirroring isArrayOverride. */
20
+ type IsArrayOverride<T> = T extends {
21
+ readonly value: readonly unknown[];
22
+ readonly mode: ArrayMergeMode;
23
+ } ? [keyof T] extends [keyof ArrayOverride<readonly unknown[]>] ? true : false : false;
24
+ /**
25
+ * For every array-typed value in T, additionally allow `{ value: <that array type>, mode: ArrayMergeMode }`.
26
+ * Distributes over unions, does not recurse into array elements, and leaves functions/primitives alone.
27
+ */
28
+ type WithArrayOverrides<T> = T extends readonly unknown[] ? T | ArrayOverride<T> : T extends AnyFunction ? T : T extends object ? { [K in keyof T]: WithArrayOverrides<T[K]>; } : T;
29
+ /**
30
+ * True if T contains (at any object depth, not inside arrays) a replace-mode wrapper. Depth is a recursion budget: when
31
+ * a call fails the generic constraint, this type runs over the full constraint (the whole tool config type), and the
32
+ * eager `{ ... }[keyof T]` walk would hit TS2615 on circular types in it (e.g. Console) and bury the real error.
33
+ */
34
+ type HasReplaceWrapper<T, Depth extends readonly unknown[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]> = Depth extends readonly [unknown, ...infer RemainingDepth] ? T extends readonly unknown[] ? false : T extends AnyFunction ? false : T extends object ? IsArrayOverride<T> extends true ? T extends {
35
+ readonly mode: "replace";
36
+ } ? true : false : true extends { [K in keyof T]: HasReplaceWrapper<T[K], RemainingDepth>; }[keyof T] ? true : false : false : false;
37
+ /** Keep only the key paths whose leaf is a replace-mode wrapper; unwrap those leaves to their `value` type. */
38
+ type DeepPickReplaceWrappers<T> = { [K in keyof T as HasReplaceWrapper<T[K]> extends true ? K : never]: IsArrayOverride<T[K]> extends true ? T[K] extends {
39
+ readonly value: infer V extends readonly unknown[];
40
+ } ? V : never : DeepPickReplaceWrappers<T[K]>; };
41
+ /** Drop key paths whose leaf is a replace-mode wrapper; unwrap merge-mode wrappers in place. */
42
+ type DeepDropReplaceWrappers<T> = { [K in keyof T as IsArrayOverride<T[K]> extends true ? T[K] extends {
43
+ readonly mode: "replace";
44
+ } ? never : K : K]: T[K] extends readonly unknown[] ? T[K] : T[K] extends AnyFunction ? T[K] : IsArrayOverride<T[K]> extends true ? T[K] extends {
45
+ readonly value: infer V extends readonly unknown[];
46
+ } ? V : never : T[K] extends object ? DeepDropReplaceWrappers<T[K]> : T[K]; };
47
+ /**
48
+ * The merged result type, exact for per-key overrides: pass 1 merges the user config minus replace-wrapper keys
49
+ * (unwrapping merge-mode wrappers, which behave like plain arrays) with array spreading; pass 2 merges the unwrapped
50
+ * replace-wrapper keys with array replacement. Instead of returning `BaseConfig & UserConfig` (from `merge`), this is a
51
+ * more friendly type via `MergeDeep`.
52
+ */
53
+ type MergedConfig<BaseConfig, UserConfig> = MergeDeep<MergeDeep<SimplifyDeep<WritableDeep<BaseConfig>>, SimplifyDeep<WritableDeep<DeepDropReplaceWrappers<UserConfig>>>, {
54
+ arrayMergeMode: "spread";
55
+ }>, SimplifyDeep<WritableDeep<DeepPickReplaceWrappers<UserConfig>>>, {
56
+ arrayMergeMode: "replace";
57
+ }>;
3
58
  /**
4
59
  * The merge config function, where the `UserConfig` passed in is merged with `BaseConfig`.
5
60
  *
6
- * Each `arrays` mode gets its own overload so the return type's `arrayMergeMode` matches the runtime behavior. The
7
- * `"replace"` overload comes first so it wins overload resolution when `{ arrays: "replace" }` is passed.
8
- *
9
61
  * The `const` type parameter keeps literal types without requiring `as const` at the call site. The constraint is
10
- * `ReadonlyDeep` so readonly arrays/objects (e.g. from `as const`) are accepted, and the result is `WritableDeep` so it
11
- * stays assignable to the tools' own (mutable) config types.
62
+ * `WithArrayOverrides<ReadonlyDeep<...>>` so readonly arrays/objects (e.g. from `as const`) are accepted and any
63
+ * array-typed key can alternatively take an ArrayOverride wrapper; the result is `WritableDeep` so it stays assignable
64
+ * to the tools' own (mutable) config types.
12
65
  */
13
- interface MergeConfigFn<UserConfig, BaseConfig> {
14
- <const UserConfigToMerge extends ReadonlyDeep<UserConfig>>(userConfig: UserConfigToMerge, options: {
15
- arrays: "replace";
16
- }): MergeDeep<SimplifyDeep<WritableDeep<BaseConfig>>, SimplifyDeep<WritableDeep<UserConfigToMerge>>, {
17
- arrayMergeMode: "replace";
18
- }>;
19
- <const UserConfigToMerge extends ReadonlyDeep<UserConfig>>(userConfig: UserConfigToMerge, options?: {
20
- arrays?: "merge";
21
- }): MergeDeep<SimplifyDeep<WritableDeep<BaseConfig>>, SimplifyDeep<WritableDeep<UserConfigToMerge>>, {
22
- arrayMergeMode: "spread";
23
- }>;
24
- }
66
+ type MergeConfigFn<UserConfig, BaseConfig> = <const UserConfigToMerge extends WithArrayOverrides<ReadonlyDeep<UserConfig>>>(userConfig: UserConfigToMerge) => MergedConfig<BaseConfig, UserConfigToMerge>;
25
67
  /**
26
68
  * The optional merge config function, where the `userConfig` argument is optional. - if `UserConfig` is not provided,
27
69
  * the return type is `BaseConfig` - if `UserConfig` is provided, the return type is the merged type of `BaseConfig` and
28
70
  * `UserConfig`.
29
71
  *
30
- * Note that this extends `MergeConfigFn`, so this type has both function signatures on it.
72
+ * CRITICAL: must stay a type-alias intersection (NOT `interface ... extends MergeConfigFn`): checking the
73
+ * interface-inheritance relation forces tsc to relate the no-arg signature's return type against the recursive
74
+ * `MergedConfig` type, which explodes to millions of type instantiations.
31
75
  */
32
- interface OptionalMergeConfigFn<UserConfig, BaseConfig> extends MergeConfigFn<UserConfig, BaseConfig> {
33
- (): SimplifyDeep<WritableDeep<BaseConfig>>;
34
- }
76
+ type OptionalMergeConfigFn<UserConfig, BaseConfig> = MergeConfigFn<UserConfig, BaseConfig> & (() => SimplifyDeep<WritableDeep<BaseConfig>>);
35
77
  //#endregion
36
78
  export { MergeConfigFn, OptionalMergeConfigFn };
37
79
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","names":[],"sources":["../src/utils.ts"],"mappings":";;;;;;;;;;;;UA+BiB,cAAc,YAAY;SAClC,0BAA0B,aAAa,aAC5C,YAAY,mBACZ;IAAW;MACV,UACD,aAAa,aAAa,cAC1B,aAAa,aAAa;IACxB;;SAEG,0BAA0B,aAAa,aAC5C,YAAY,mBACZ;IAAY;MACX,UACD,aAAa,aAAa,cAC1B,aAAa,aAAa;IACxB;;;;;;;;;;UAYW,sBAAsB,YAAY,oBAAoB,cAAc,YAAY;MAC3F,aAAa,aAAa"}
1
+ {"version":3,"file":"utils.d.ts","names":[],"sources":["../src/utils.ts"],"mappings":";;KAIK,kBAAkB;;;;;KAMlB;;;;;;;UAQK,cAAc,kCAAkC,aAAa,iBAAiB;WAC7E,OAAO;WACP,MAAM;;;KAiCZ,gBAAgB,KAAK;WAAqB;WAAoC,MAAM;WAC9E,kBAAkB;;;;;KASxB,mBAAmB,KAAK,+BACzB,IAAI,cAAc,KAClB,UAAU,cACR,IACA,sBACK,WAAW,IAAI,mBAAmB,EAAE,SACvC;;;;;;KAOH,kBAAkB,GAAG,qEAAqE,0CAEpF,kBAEP,uCAEE,UAAU,sBAER,mBACE,gBAAgB,kBACd;WAAqB;mCAGL,WAAW,IAAI,kBAAkB,EAAE,IAAI,yBAAwB;;KAOtF,wBAAwB,QAC1B,WAAW,KAAK,kBAAkB,EAAE,mBAAmB,YAAY,gBAAgB,EAAE,mBAClF,EAAE;WAAsB,aAAa;IACnC,YAEF,wBAAwB,EAAE;;KAI3B,wBAAwB,QAC1B,WAAW,KAAK,gBAAgB,EAAE,mBAC/B,EAAE;WAAsB;YAEtB,IACF,IAAI,EAAE,gCACN,EAAE,KACF,EAAE,WAAW,cACX,EAAE,KACF,gBAAgB,EAAE,mBAChB,EAAE;WAAsB,aAAa;IACnC,YAEF,EAAE,oBACA,wBAAwB,EAAE,MAC1B,EAAE;;;;;;;KAST,aAAa,YAAY,cAAc,UAC1C,UACE,aAAa,aAAa,cAC1B,aAAa,aAAa,wBAAwB;EAChD;IAEJ,aAAa,aAAa,wBAAwB;EAChD;;;;;;;;;;KAWQ,cAAc,YAAY,qBAC9B,0BAA0B,mBAAmB,aAAa,cAEhE,YAAY,sBACT,aAAa,YAAY;;;;;;;;;;KAWlB,sBAAsB,YAAY,cAAc,cAAc,YAAY,qBAC7E,aAAa,aAAa"}
package/dist/utils.js CHANGED
@@ -1,15 +1,32 @@
1
- import { cloneDeep, mergeWith } from "es-toolkit";
1
+ import { cloneDeep, isPlainObject, mergeWith } from "es-toolkit";
2
2
  //#region src/utils.ts
3
- /** A wrapper around es-toolkit's `mergeWith` with a custom merge function that concatenates or replaces arrays. */
4
- const merge = (target, source, arrays) => mergeWith(target, source, (objValue, srcValue) => {
3
+ /** Runtime wrapper check, mirrored by IsArrayOverride: plain object with exactly the keys value (array) + mode. */
4
+ const isArrayOverride = (v) => {
5
+ if (!isPlainObject(v)) return false;
6
+ if (Object.keys(v).length !== 2) return false;
7
+ const { value } = v;
8
+ const { mode } = v;
9
+ return Array.isArray(value) && (mode === "merge" || mode === "replace");
10
+ };
11
+ /**
12
+ * A wrapper around es-toolkit's `mergeWith` with a custom merge function that concatenates arrays, honoring per-key
13
+ * ArrayOverride wrappers. Wrapper interception must come first: the default path would deep-merge the wrapper as a
14
+ * plain object.
15
+ */
16
+ const merge = (target, source) => mergeWith(target, source, (objValue, srcValue) => {
17
+ if (isArrayOverride(srcValue)) {
18
+ const { value: userArray, mode } = srcValue;
19
+ if (!Array.isArray(objValue)) return userArray;
20
+ return mode === "merge" ? [...objValue, ...userArray] : userArray;
21
+ }
5
22
  if (!Array.isArray(objValue)) return;
6
23
  if (!Array.isArray(srcValue)) return srcValue;
7
24
  const baseArray = objValue;
8
25
  const userArray = srcValue;
9
- return arrays === "merge" ? [...baseArray, ...userArray] : userArray;
26
+ return [...baseArray, ...userArray];
10
27
  });
11
28
  /**
12
- * Creates a config merge function with proper type overloads for merging with a base config.
29
+ * Creates a config merge function with proper types for merging with a base config.
13
30
  *
14
31
  * `UserConfig` is not inferrable, so both type arguments must be passed explicitly. Returning the exact
15
32
  * `OptionalMergeConfigFn` instantiation (instead of relating a looser type to an annotation at the export site) keeps
@@ -17,9 +34,9 @@ const merge = (target, source, arrays) => mergeWith(target, source, (objValue, s
17
34
  * limit on large configs like tsdown's.
18
35
  */
19
36
  const createMergeConfigFn = (baseConfig) => {
20
- const mergeConfigFn = (userConfig, options) => {
37
+ const mergeConfigFn = (userConfig) => {
21
38
  if (userConfig === void 0) return cloneDeep(baseConfig);
22
- return merge(cloneDeep(baseConfig), cloneDeep(userConfig), options?.arrays ?? "merge");
39
+ return merge(cloneDeep(baseConfig), cloneDeep(userConfig));
23
40
  };
24
41
  return mergeConfigFn;
25
42
  };
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import { cloneDeep, mergeWith } from \"es-toolkit\"\nimport type { MergeDeep, ReadonlyDeep, WritableDeep, SimplifyDeep } from \"type-fest\"\n\ntype AnyObj = object\n\n/**\n * How arrays in the user config are combined with arrays in the base config. - `\"merge\"` (default): the user array is\n * appended to the base array - `\"replace\"`: the user array is used as-is\n */\ntype ArrayMergeMode = \"merge\" | \"replace\"\n\n/** A wrapper around es-toolkit's `mergeWith` with a custom merge function that concatenates or replaces arrays. */\nconst merge = <T extends AnyObj, S extends AnyObj>(target: T, source: S, arrays: ArrayMergeMode): T & S =>\n mergeWith(target, source, (objValue: unknown, srcValue: unknown) => {\n if (!Array.isArray(objValue)) return\n if (!Array.isArray(srcValue)) return srcValue\n const baseArray: unknown[] = objValue\n const userArray: unknown[] = srcValue\n return arrays === \"merge\" ? [...baseArray, ...userArray] : userArray\n })\n\n/**\n * The merge config function, where the `UserConfig` passed in is merged with `BaseConfig`.\n *\n * Each `arrays` mode gets its own overload so the return type's `arrayMergeMode` matches the runtime behavior. The\n * `\"replace\"` overload comes first so it wins overload resolution when `{ arrays: \"replace\" }` is passed.\n *\n * The `const` type parameter keeps literal types without requiring `as const` at the call site. The constraint is\n * `ReadonlyDeep` so readonly arrays/objects (e.g. from `as const`) are accepted, and the result is `WritableDeep` so it\n * stays assignable to the tools' own (mutable) config types.\n */\nexport interface MergeConfigFn<UserConfig, BaseConfig> {\n <const UserConfigToMerge extends ReadonlyDeep<UserConfig>>(\n userConfig: UserConfigToMerge,\n options: { arrays: \"replace\" },\n ): MergeDeep<\n SimplifyDeep<WritableDeep<BaseConfig>>,\n SimplifyDeep<WritableDeep<UserConfigToMerge>>,\n { arrayMergeMode: \"replace\" }\n >\n <const UserConfigToMerge extends ReadonlyDeep<UserConfig>>(\n userConfig: UserConfigToMerge,\n options?: { arrays?: \"merge\" },\n ): MergeDeep<\n SimplifyDeep<WritableDeep<BaseConfig>>,\n SimplifyDeep<WritableDeep<UserConfigToMerge>>,\n { arrayMergeMode: \"spread\" }\n >\n // Instead of returning `BaseConfig & UserConfig` (from `merge`), return a more friendly type using `MergeDeep`\n}\n\n/**\n * The optional merge config function, where the `userConfig` argument is optional. - if `UserConfig` is not provided,\n * the return type is `BaseConfig` - if `UserConfig` is provided, the return type is the merged type of `BaseConfig` and\n * `UserConfig`.\n *\n * Note that this extends `MergeConfigFn`, so this type has both function signatures on it.\n */\nexport interface OptionalMergeConfigFn<UserConfig, BaseConfig> extends MergeConfigFn<UserConfig, BaseConfig> {\n (): SimplifyDeep<WritableDeep<BaseConfig>>\n}\n\n/**\n * Creates a config merge function with proper type overloads for merging with a base config.\n *\n * `UserConfig` is not inferrable, so both type arguments must be passed explicitly. Returning the exact\n * `OptionalMergeConfigFn` instantiation (instead of relating a looser type to an annotation at the export site) keeps\n * tsc from eagerly evaluating the deep-mapped types over the full config type, which blows the instantiation depth\n * limit on large configs like tsdown's.\n */\nexport const createMergeConfigFn = <UserConfig extends AnyObj, BaseConfig extends ReadonlyDeep<UserConfig>>(\n baseConfig: BaseConfig,\n): OptionalMergeConfigFn<UserConfig, BaseConfig> => {\n // We don't care about the specific type of userConfig here because we assert mergeConfigFn as the correct type below\n const mergeConfigFn = (userConfig?: AnyObj, options?: { arrays?: ArrayMergeMode }) => {\n // Return a clone so consumers can't mutate the shared base config\n // oxlint-disable-next-line unicorn/prefer-structured-clone - structuredClone does not properly clone functions\n if (userConfig === undefined) return cloneDeep(baseConfig)\n // Clone both target and source so we never mutate the original objects\n // oxlint-disable-next-line unicorn/prefer-structured-clone - structuredClone does not properly clone functions\n return merge(cloneDeep(baseConfig), cloneDeep(userConfig), options?.arrays ?? \"merge\")\n }\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion\n return mergeConfigFn as OptionalMergeConfigFn<UserConfig, BaseConfig>\n}\n"],"mappings":";;;AAYA,MAAM,SAA6C,QAAW,QAAW,WACvE,UAAU,QAAQ,SAAS,UAAmB,aAAsB;CAClE,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG;CAC9B,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG,OAAO;CACrC,MAAM,YAAuB;CAC7B,MAAM,YAAuB;CAC7B,OAAO,WAAW,UAAU,CAAC,GAAG,WAAW,GAAG,SAAS,IAAI;AAC7D,CAAC;;;;;;;;;AAmDH,MAAa,uBACX,eACkD;CAElD,MAAM,iBAAiB,YAAqB,YAA0C;EAGpF,IAAI,eAAe,KAAA,GAAW,OAAO,UAAU,UAAU;EAGzD,OAAO,MAAM,UAAU,UAAU,GAAG,UAAU,UAAU,GAAG,SAAS,UAAU,OAAO;CACvF;CAGA,OAAO;AACT"}
1
+ {"version":3,"file":"utils.js","names":["baseArray"],"sources":["../src/utils.ts"],"sourcesContent":["import { cloneDeep, isPlainObject, mergeWith } from \"es-toolkit\"\nimport type { MergeDeep, ReadonlyDeep, WritableDeep, SimplifyDeep } from \"type-fest\"\n\ntype AnyObj = object\ntype AnyFunction = (...args: never[]) => unknown\n\n/**\n * How a wrapped user array is combined with the base array. - `\"merge\"` (the default for plain arrays): the user array\n * is appended to the base array - `\"replace\"`: the user array is used as-is\n */\ntype ArrayMergeMode = \"merge\" | \"replace\"\n\n/**\n * A per-key array override. Wherever a config key takes an array, `{ value: [...], mode: \"merge\" | \"replace\" }` may be\n * passed instead; `mode` controls how that key's array combines with the base config's. The wrapper never appears in\n * the merged result. A config value that is exactly this shape is always consumed as a wrapper; an object with extra\n * keys is treated as a plain config object.\n */\ninterface ArrayOverride<Value extends readonly unknown[], Mode extends ArrayMergeMode = ArrayMergeMode> {\n readonly value: Value\n readonly mode: Mode\n}\n\n/** Runtime wrapper check, mirrored by IsArrayOverride: plain object with exactly the keys value (array) + mode. */\nconst isArrayOverride = (v: unknown): v is { value: unknown[]; mode: ArrayMergeMode } => {\n if (!isPlainObject(v)) return false\n if (Object.keys(v).length !== 2) return false\n const { value } = v\n const { mode } = v\n return Array.isArray(value) && (mode === \"merge\" || mode === \"replace\")\n}\n\n/**\n * A wrapper around es-toolkit's `mergeWith` with a custom merge function that concatenates arrays, honoring per-key\n * ArrayOverride wrappers. Wrapper interception must come first: the default path would deep-merge the wrapper as a\n * plain object.\n */\nconst merge = <T extends AnyObj, S extends AnyObj>(target: T, source: S): T & S =>\n mergeWith(target, source, (objValue: unknown, srcValue: unknown) => {\n if (isArrayOverride(srcValue)) {\n const { value: userArray, mode } = srcValue\n if (!Array.isArray(objValue)) return userArray\n const baseArray: unknown[] = objValue\n return mode === \"merge\" ? [...baseArray, ...userArray] : userArray\n }\n if (!Array.isArray(objValue)) return\n if (!Array.isArray(srcValue)) return srcValue\n const baseArray: unknown[] = objValue\n const userArray: unknown[] = srcValue\n return [...baseArray, ...userArray]\n })\n\n/** True only when T is exactly the wrapper shape (keys value + mode, nothing else), mirroring isArrayOverride. */\ntype IsArrayOverride<T> = T extends { readonly value: readonly unknown[]; readonly mode: ArrayMergeMode }\n ? [keyof T] extends [keyof ArrayOverride<readonly unknown[]>]\n ? true\n : false\n : false\n\n/**\n * For every array-typed value in T, additionally allow `{ value: <that array type>, mode: ArrayMergeMode }`.\n * Distributes over unions, does not recurse into array elements, and leaves functions/primitives alone.\n */\ntype WithArrayOverrides<T> = T extends readonly unknown[]\n ? T | ArrayOverride<T>\n : T extends AnyFunction\n ? T\n : T extends object\n ? { [K in keyof T]: WithArrayOverrides<T[K]> }\n : T\n\n/**\n * True if T contains (at any object depth, not inside arrays) a replace-mode wrapper. Depth is a recursion budget: when\n * a call fails the generic constraint, this type runs over the full constraint (the whole tool config type), and the\n * eager `{ ... }[keyof T]` walk would hit TS2615 on circular types in it (e.g. Console) and bury the real error.\n */\ntype HasReplaceWrapper<T, Depth extends readonly unknown[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]> = Depth extends readonly [\n unknown,\n ...infer RemainingDepth,\n]\n ? T extends readonly unknown[]\n ? false\n : T extends AnyFunction\n ? false\n : T extends object\n ? IsArrayOverride<T> extends true\n ? T extends { readonly mode: \"replace\" }\n ? true\n : false\n : true extends { [K in keyof T]: HasReplaceWrapper<T[K], RemainingDepth> }[keyof T]\n ? true\n : false\n : false\n : false\n\n/** Keep only the key paths whose leaf is a replace-mode wrapper; unwrap those leaves to their `value` type. */\ntype DeepPickReplaceWrappers<T> = {\n [K in keyof T as HasReplaceWrapper<T[K]> extends true ? K : never]: IsArrayOverride<T[K]> extends true\n ? T[K] extends { readonly value: infer V extends readonly unknown[] }\n ? V\n : never\n : DeepPickReplaceWrappers<T[K]>\n}\n\n/** Drop key paths whose leaf is a replace-mode wrapper; unwrap merge-mode wrappers in place. */\ntype DeepDropReplaceWrappers<T> = {\n [K in keyof T as IsArrayOverride<T[K]> extends true\n ? T[K] extends { readonly mode: \"replace\" }\n ? never\n : K\n : K]: T[K] extends readonly unknown[]\n ? T[K]\n : T[K] extends AnyFunction\n ? T[K]\n : IsArrayOverride<T[K]> extends true\n ? T[K] extends { readonly value: infer V extends readonly unknown[] }\n ? V\n : never\n : T[K] extends object\n ? DeepDropReplaceWrappers<T[K]>\n : T[K]\n}\n\n/**\n * The merged result type, exact for per-key overrides: pass 1 merges the user config minus replace-wrapper keys\n * (unwrapping merge-mode wrappers, which behave like plain arrays) with array spreading; pass 2 merges the unwrapped\n * replace-wrapper keys with array replacement. Instead of returning `BaseConfig & UserConfig` (from `merge`), this is a\n * more friendly type via `MergeDeep`.\n */\ntype MergedConfig<BaseConfig, UserConfig> = MergeDeep<\n MergeDeep<\n SimplifyDeep<WritableDeep<BaseConfig>>,\n SimplifyDeep<WritableDeep<DeepDropReplaceWrappers<UserConfig>>>,\n { arrayMergeMode: \"spread\" }\n >,\n SimplifyDeep<WritableDeep<DeepPickReplaceWrappers<UserConfig>>>,\n { arrayMergeMode: \"replace\" }\n>\n\n/**\n * The merge config function, where the `UserConfig` passed in is merged with `BaseConfig`.\n *\n * The `const` type parameter keeps literal types without requiring `as const` at the call site. The constraint is\n * `WithArrayOverrides<ReadonlyDeep<...>>` so readonly arrays/objects (e.g. from `as const`) are accepted and any\n * array-typed key can alternatively take an ArrayOverride wrapper; the result is `WritableDeep` so it stays assignable\n * to the tools' own (mutable) config types.\n */\nexport type MergeConfigFn<UserConfig, BaseConfig> = <\n const UserConfigToMerge extends WithArrayOverrides<ReadonlyDeep<UserConfig>>,\n>(\n userConfig: UserConfigToMerge,\n) => MergedConfig<BaseConfig, UserConfigToMerge>\n\n/**\n * The optional merge config function, where the `userConfig` argument is optional. - if `UserConfig` is not provided,\n * the return type is `BaseConfig` - if `UserConfig` is provided, the return type is the merged type of `BaseConfig` and\n * `UserConfig`.\n *\n * CRITICAL: must stay a type-alias intersection (NOT `interface ... extends MergeConfigFn`): checking the\n * interface-inheritance relation forces tsc to relate the no-arg signature's return type against the recursive\n * `MergedConfig` type, which explodes to millions of type instantiations.\n */\nexport type OptionalMergeConfigFn<UserConfig, BaseConfig> = MergeConfigFn<UserConfig, BaseConfig> &\n (() => SimplifyDeep<WritableDeep<BaseConfig>>)\n\n/**\n * Creates a config merge function with proper types for merging with a base config.\n *\n * `UserConfig` is not inferrable, so both type arguments must be passed explicitly. Returning the exact\n * `OptionalMergeConfigFn` instantiation (instead of relating a looser type to an annotation at the export site) keeps\n * tsc from eagerly evaluating the deep-mapped types over the full config type, which blows the instantiation depth\n * limit on large configs like tsdown's.\n */\nexport const createMergeConfigFn = <UserConfig extends AnyObj, BaseConfig extends ReadonlyDeep<UserConfig>>(\n baseConfig: BaseConfig,\n): OptionalMergeConfigFn<UserConfig, BaseConfig> => {\n // We don't care about the specific type of userConfig here because we assert mergeConfigFn as the correct type below\n const mergeConfigFn = (userConfig?: AnyObj) => {\n // Return a clone so consumers can't mutate the shared base config\n // oxlint-disable-next-line unicorn/prefer-structured-clone - structuredClone does not properly clone functions\n if (userConfig === undefined) return cloneDeep(baseConfig)\n // Clone both target and source so we never mutate the original objects\n // oxlint-disable-next-line unicorn/prefer-structured-clone - structuredClone does not properly clone functions\n return merge(cloneDeep(baseConfig), cloneDeep(userConfig))\n }\n\n // CRITICAL: two-step assertion required: a direct cast makes tsc run a comparability check relating the\n // implementation signature against the recursive MergedConfig type (millions of instantiations).\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion\n return mergeConfigFn as unknown as OptionalMergeConfigFn<UserConfig, BaseConfig>\n}\n"],"mappings":";;;AAwBA,MAAM,mBAAmB,MAAgE;CACvF,IAAI,CAAC,cAAc,CAAC,GAAG,OAAO;CAC9B,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,WAAW,GAAG,OAAO;CACxC,MAAM,EAAE,UAAU;CAClB,MAAM,EAAE,SAAS;CACjB,OAAO,MAAM,QAAQ,KAAK,MAAM,SAAS,WAAW,SAAS;AAC/D;;;;;;AAOA,MAAM,SAA6C,QAAW,WAC5D,UAAU,QAAQ,SAAS,UAAmB,aAAsB;CAClE,IAAI,gBAAgB,QAAQ,GAAG;EAC7B,MAAM,EAAE,OAAO,WAAW,SAAS;EACnC,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG,OAAO;EAErC,OAAO,SAAS,UAAU,CAAC,GAAGA,UAAW,GAAG,SAAS,IAAI;CAC3D;CACA,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG;CAC9B,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG,OAAO;CACrC,MAAM,YAAuB;CAC7B,MAAM,YAAuB;CAC7B,OAAO,CAAC,GAAG,WAAW,GAAG,SAAS;AACpC,CAAC;;;;;;;;;AA2HH,MAAa,uBACX,eACkD;CAElD,MAAM,iBAAiB,eAAwB;EAG7C,IAAI,eAAe,KAAA,GAAW,OAAO,UAAU,UAAU;EAGzD,OAAO,MAAM,UAAU,UAAU,GAAG,UAAU,UAAU,CAAC;CAC3D;CAKA,OAAO;AACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adamhl8/configs",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "My shared configs for TS projects",
5
5
  "homepage": "https://github.com/adamhl8/configs",
6
6
  "bugs": {