ioc-manifest 0.3.0

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.
Files changed (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +350 -0
  3. package/bin/ioc.cjs +19 -0
  4. package/dist/cli/ioc.d.ts +3 -0
  5. package/dist/cli/ioc.d.ts.map +1 -0
  6. package/dist/cli/ioc.js +86 -0
  7. package/dist/cli/ioc.js.map +1 -0
  8. package/dist/cli/parseIocCli.d.ts +21 -0
  9. package/dist/cli/parseIocCli.d.ts.map +1 -0
  10. package/dist/cli/parseIocCli.js +76 -0
  11. package/dist/cli/parseIocCli.js.map +1 -0
  12. package/dist/config/iocConfig.d.ts +97 -0
  13. package/dist/config/iocConfig.d.ts.map +1 -0
  14. package/dist/config/iocConfig.js +65 -0
  15. package/dist/config/iocConfig.js.map +1 -0
  16. package/dist/config/loadIocConfig.d.ts +25 -0
  17. package/dist/config/loadIocConfig.d.ts.map +1 -0
  18. package/dist/config/loadIocConfig.js +245 -0
  19. package/dist/config/loadIocConfig.js.map +1 -0
  20. package/dist/config/parseDiscoveryScanDirs.d.ts +6 -0
  21. package/dist/config/parseDiscoveryScanDirs.d.ts.map +1 -0
  22. package/dist/config/parseDiscoveryScanDirs.js +78 -0
  23. package/dist/config/parseDiscoveryScanDirs.js.map +1 -0
  24. package/dist/core/defaultImplementationSelection.d.ts +14 -0
  25. package/dist/core/defaultImplementationSelection.d.ts.map +1 -0
  26. package/dist/core/defaultImplementationSelection.js +47 -0
  27. package/dist/core/defaultImplementationSelection.js.map +1 -0
  28. package/dist/core/index.d.ts +4 -0
  29. package/dist/core/index.d.ts.map +1 -0
  30. package/dist/core/index.js +3 -0
  31. package/dist/core/index.js.map +1 -0
  32. package/dist/core/manifest.d.ts +79 -0
  33. package/dist/core/manifest.d.ts.map +1 -0
  34. package/dist/core/manifest.js +3 -0
  35. package/dist/core/manifest.js.map +1 -0
  36. package/dist/core/resolver.d.ts +18 -0
  37. package/dist/core/resolver.d.ts.map +1 -0
  38. package/dist/core/resolver.js +27 -0
  39. package/dist/core/resolver.js.map +1 -0
  40. package/dist/generator/contractTypeSourceFile.d.ts +16 -0
  41. package/dist/generator/contractTypeSourceFile.d.ts.map +1 -0
  42. package/dist/generator/contractTypeSourceFile.js +236 -0
  43. package/dist/generator/contractTypeSourceFile.js.map +1 -0
  44. package/dist/generator/discoverFactories/discoverFactories.d.ts +18 -0
  45. package/dist/generator/discoverFactories/discoverFactories.d.ts.map +1 -0
  46. package/dist/generator/discoverFactories/discoverFactories.js +108 -0
  47. package/dist/generator/discoverFactories/discoverFactories.js.map +1 -0
  48. package/dist/generator/discoverFactories/discoveryOutcomeTypes.d.ts +47 -0
  49. package/dist/generator/discoverFactories/discoveryOutcomeTypes.d.ts.map +1 -0
  50. package/dist/generator/discoverFactories/discoveryOutcomeTypes.js +19 -0
  51. package/dist/generator/discoverFactories/discoveryOutcomeTypes.js.map +1 -0
  52. package/dist/generator/discoverFactories/inferFactoryDependencyContracts.d.ts +11 -0
  53. package/dist/generator/discoverFactories/inferFactoryDependencyContracts.d.ts.map +1 -0
  54. package/dist/generator/discoverFactories/inferFactoryDependencyContracts.js +118 -0
  55. package/dist/generator/discoverFactories/inferFactoryDependencyContracts.js.map +1 -0
  56. package/dist/generator/discoverFactories/scanFactoryFile.d.ts +18 -0
  57. package/dist/generator/discoverFactories/scanFactoryFile.d.ts.map +1 -0
  58. package/dist/generator/discoverFactories/scanFactoryFile.js +379 -0
  59. package/dist/generator/discoverFactories/scanFactoryFile.js.map +1 -0
  60. package/dist/generator/generateManifest.d.ts +13 -0
  61. package/dist/generator/generateManifest.d.ts.map +1 -0
  62. package/dist/generator/generateManifest.js +88 -0
  63. package/dist/generator/generateManifest.js.map +1 -0
  64. package/dist/generator/iocProgramContext.d.ts +11 -0
  65. package/dist/generator/iocProgramContext.d.ts.map +1 -0
  66. package/dist/generator/iocProgramContext.js +81 -0
  67. package/dist/generator/iocProgramContext.js.map +1 -0
  68. package/dist/generator/manifestOptions.d.ts +26 -0
  69. package/dist/generator/manifestOptions.d.ts.map +1 -0
  70. package/dist/generator/manifestOptions.js +86 -0
  71. package/dist/generator/manifestOptions.js.map +1 -0
  72. package/dist/generator/manifestPaths.d.ts +94 -0
  73. package/dist/generator/manifestPaths.d.ts.map +1 -0
  74. package/dist/generator/manifestPaths.js +377 -0
  75. package/dist/generator/manifestPaths.js.map +1 -0
  76. package/dist/generator/naming.d.ts +9 -0
  77. package/dist/generator/naming.d.ts.map +1 -0
  78. package/dist/generator/naming.js +46 -0
  79. package/dist/generator/naming.js.map +1 -0
  80. package/dist/generator/resolveRegistrationPlan.d.ts +66 -0
  81. package/dist/generator/resolveRegistrationPlan.d.ts.map +1 -0
  82. package/dist/generator/resolveRegistrationPlan.js +377 -0
  83. package/dist/generator/resolveRegistrationPlan.js.map +1 -0
  84. package/dist/generator/types.d.ts +37 -0
  85. package/dist/generator/types.d.ts.map +1 -0
  86. package/dist/generator/types.js +2 -0
  87. package/dist/generator/types.js.map +1 -0
  88. package/dist/generator/writeManifest.d.ts +19 -0
  89. package/dist/generator/writeManifest.d.ts.map +1 -0
  90. package/dist/generator/writeManifest.js +405 -0
  91. package/dist/generator/writeManifest.js.map +1 -0
  92. package/dist/groups/baseTypeAssignability.d.ts +48 -0
  93. package/dist/groups/baseTypeAssignability.d.ts.map +1 -0
  94. package/dist/groups/baseTypeAssignability.js +145 -0
  95. package/dist/groups/baseTypeAssignability.js.map +1 -0
  96. package/dist/groups/resolveGroupPlan.d.ts +85 -0
  97. package/dist/groups/resolveGroupPlan.d.ts.map +1 -0
  98. package/dist/groups/resolveGroupPlan.js +215 -0
  99. package/dist/groups/resolveGroupPlan.js.map +1 -0
  100. package/dist/index.d.ts +22 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +20 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/inspection/formatReports.d.ts +14 -0
  105. package/dist/inspection/formatReports.d.ts.map +1 -0
  106. package/dist/inspection/formatReports.js +115 -0
  107. package/dist/inspection/formatReports.js.map +1 -0
  108. package/dist/inspection/index.d.ts +8 -0
  109. package/dist/inspection/index.d.ts.map +1 -0
  110. package/dist/inspection/index.js +8 -0
  111. package/dist/inspection/index.js.map +1 -0
  112. package/dist/inspection/reports.d.ts +40 -0
  113. package/dist/inspection/reports.d.ts.map +1 -0
  114. package/dist/inspection/reports.js +95 -0
  115. package/dist/inspection/reports.js.map +1 -0
  116. package/dist/inspection/runDiscoveryAnalysis.d.ts +36 -0
  117. package/dist/inspection/runDiscoveryAnalysis.d.ts.map +1 -0
  118. package/dist/inspection/runDiscoveryAnalysis.js +48 -0
  119. package/dist/inspection/runDiscoveryAnalysis.js.map +1 -0
  120. package/dist/inspection/validateManifest.d.ts +8 -0
  121. package/dist/inspection/validateManifest.d.ts.map +1 -0
  122. package/dist/inspection/validateManifest.js +46 -0
  123. package/dist/inspection/validateManifest.js.map +1 -0
  124. package/dist/runtime/bootstrap.d.ts +13 -0
  125. package/dist/runtime/bootstrap.d.ts.map +1 -0
  126. package/dist/runtime/bootstrap.js +259 -0
  127. package/dist/runtime/bootstrap.js.map +1 -0
  128. package/dist/runtime/index.d.ts +4 -0
  129. package/dist/runtime/index.d.ts.map +1 -0
  130. package/dist/runtime/index.js +4 -0
  131. package/dist/runtime/index.js.map +1 -0
  132. package/dist/runtime/iocResolutionError.d.ts +54 -0
  133. package/dist/runtime/iocResolutionError.d.ts.map +1 -0
  134. package/dist/runtime/iocResolutionError.js +266 -0
  135. package/dist/runtime/iocResolutionError.js.map +1 -0
  136. package/dist/runtime/iocResolutionStack.d.ts +21 -0
  137. package/dist/runtime/iocResolutionStack.d.ts.map +1 -0
  138. package/dist/runtime/iocResolutionStack.js +17 -0
  139. package/dist/runtime/iocResolutionStack.js.map +1 -0
  140. package/dist/runtime/iocRuntimeErrors.d.ts +35 -0
  141. package/dist/runtime/iocRuntimeErrors.d.ts.map +1 -0
  142. package/dist/runtime/iocRuntimeErrors.js +27 -0
  143. package/dist/runtime/iocRuntimeErrors.js.map +1 -0
  144. package/dist/runtime/registrationKeyIndex.d.ts +12 -0
  145. package/dist/runtime/registrationKeyIndex.d.ts.map +1 -0
  146. package/dist/runtime/registrationKeyIndex.js +19 -0
  147. package/dist/runtime/registrationKeyIndex.js.map +1 -0
  148. package/package.json +67 -0
@@ -0,0 +1,97 @@
1
+ import type { IocGroupsConfig } from "../groups/resolveGroupPlan.js";
2
+ export type IocLifetime = "singleton" | "scoped" | "transient";
3
+ /** Reserved key under `registrations[ContractName]` for contract-level metadata (not an implementation). */
4
+ export declare const IOC_CONTRACT_CONFIG_KEY: "$contract";
5
+ /**
6
+ * Contract-level options under `registrations[ContractName][IOC_CONTRACT_CONFIG_KEY]`.
7
+ * Separate from per-implementation {@link IocOverride} entries.
8
+ */
9
+ export type IocContractMetadata = {
10
+ /**
11
+ * Cradle / default-slot key for this contract (singular exposure). When omitted, derived from the
12
+ * contract name (e.g. `Knex` → `knex`).
13
+ */
14
+ accessKey?: string;
15
+ };
16
+ /**
17
+ * Per-implementation overrides in `ioc.config` only (never read from factory modules).
18
+ * `name` sets the Awilix registration key (maps to internal `registrationKey`).
19
+ */
20
+ export type IocOverride = {
21
+ /** Awilix/container registration key; applied as `registrationKey` during planning. */
22
+ name?: string;
23
+ lifetime?: IocLifetime;
24
+ default?: boolean;
25
+ };
26
+ export type IocRegistrationsPerContract = Record<string, IocOverride | IocContractMetadata>;
27
+ export declare const parseContractLevelConfig: (entry: unknown, pathForError: string) => IocContractMetadata;
28
+ export declare const getContractLevelConfig: (perContract: IocRegistrationsPerContract | undefined, contractLabel: string) => IocContractMetadata;
29
+ /** True when the value is per-implementation config (not a misplaced `$contract` object). */
30
+ export declare const isIocImplementationOverride: (value: IocOverride | IocContractMetadata) => value is IocOverride;
31
+ export declare const getImplOverrideForImplementation: (perContract: IocRegistrationsPerContract | undefined, implementationName: string) => IocOverride | undefined;
32
+ /** How manifest import specifiers are built when {@link IocScanDirSpec.importPrefix} is set. */
33
+ export type IocScanDirImportMode = "root" | "subpath";
34
+ /**
35
+ * Maps a workspace source root to the public import specifier used in generated type-only imports
36
+ * (e.g. `{ root: "packages/lib/src", importBase: "@acme/lib" }`).
37
+ */
38
+ export type IocWorkspacePackageImportBase = {
39
+ /**
40
+ * Directory root (relative to the IoC package root from {@link resolveProjectRootFromIocConfigPath}
41
+ * unless absolute). If that path does not exist — e.g. `packages/foo` lives at the monorepo root
42
+ * but `ioc.config.ts` is under `apps/web` — the resolver walks up ancestors until it finds an
43
+ * existing directory (see {@link resolveWorkspacePackageRoot}).
44
+ */
45
+ root: string;
46
+ /** Bare module specifier for imports (no file extensions). */
47
+ importBase: string;
48
+ };
49
+ /**
50
+ * One discovery root with optional workspace/package import mapping.
51
+ * `importPrefix` + `importMode` control emitted `import` specifiers; omit both for normal relative imports from the generated dir.
52
+ */
53
+ export type IocScanDirSpec = {
54
+ path: string;
55
+ /** Package or path alias (e.g. `@packages/my-package`). Requires `importMode` when set. */
56
+ importPrefix?: string;
57
+ /** Required when `importPrefix` is set. */
58
+ importMode?: IocScanDirImportMode;
59
+ /**
60
+ * Default Awilix registration lifetime for factories discovered under this root (unless overridden
61
+ * by `registrations[Contract][implementation]`).
62
+ */
63
+ scope?: IocLifetime;
64
+ };
65
+ /**
66
+ * - `string`: single directory (relative to package root unless absolute)
67
+ * - `string[]`: multiple directories
68
+ * - `IocScanDirSpec[]`: directories with optional `importPrefix` / `importMode` for manifest imports
69
+ */
70
+ export type IocDiscoveryScanDirs = string | string[] | IocScanDirSpec[];
71
+ export type IocConfig = {
72
+ discovery: {
73
+ scanDirs: IocDiscoveryScanDirs;
74
+ includes?: string[];
75
+ excludes?: string[];
76
+ factoryPrefix?: string;
77
+ /** Output directory relative to the package root unless absolute. Default: `"generated"`. */
78
+ generatedDir?: string;
79
+ /**
80
+ * When a contract type resolves to a file under `root`, emit `importBase` instead of a long
81
+ * relative path. Longest matching `root` wins. Checked before `scanDirs` importPrefix/subpath
82
+ * mapping so public entrypoints can win over deep subpath emission.
83
+ *
84
+ * Roots are resolved against the IoC package directory (parent of `src` when the config lives
85
+ * under `src/`). Monorepo `packages/…` paths are found by walking up to the repo root when needed.
86
+ */
87
+ workspacePackageImportBases?: IocWorkspacePackageImportBase[];
88
+ };
89
+ registrations?: Record<string, IocRegistrationsPerContract>;
90
+ /**
91
+ * Group registrations by assignability to a named `baseType` (interface or type alias in the program).
92
+ * See {@link IocGroupsConfig}.
93
+ */
94
+ groups?: IocGroupsConfig;
95
+ };
96
+ export declare const defineIocConfig: (config: IocConfig) => IocConfig;
97
+ //# sourceMappingURL=iocConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iocConfig.d.ts","sourceRoot":"","sources":["../../src/config/iocConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAErE,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE/D,4GAA4G;AAC5G,eAAO,MAAM,uBAAuB,EAAG,WAAoB,CAAC;AAE5D;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG,MAAM,CAC9C,MAAM,EACN,WAAW,GAAG,mBAAmB,CAClC,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,OAAO,OAAO,EACd,cAAc,MAAM,KACnB,mBA8BF,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,aAAa,2BAA2B,GAAG,SAAS,EACpD,eAAe,MAAM,KACpB,mBAYF,CAAC;AAEF,6FAA6F;AAC7F,eAAO,MAAM,2BAA2B,GACtC,OAAO,WAAW,GAAG,mBAAmB,KACvC,KAAK,IAAI,WAWX,CAAC;AAEF,eAAO,MAAM,gCAAgC,GAC3C,aAAa,2BAA2B,GAAG,SAAS,EACpD,oBAAoB,MAAM,KACzB,WAAW,GAAG,SAYhB,CAAC;AAEF,gGAAgG;AAChG,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEtD;;;GAGG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,2FAA2F;IAC3F,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC;;;OAGG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;AAExE,MAAM,MAAM,SAAS,GAAG;IACtB,SAAS,EAAE;QACT,QAAQ,EAAE,oBAAoB,CAAC;QAC/B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,6FAA6F;QAC7F,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB;;;;;;;WAOG;QACH,2BAA2B,CAAC,EAAE,6BAA6B,EAAE,CAAC;KAC/D,CAAC;IACF,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC;IAC5D;;;OAGG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,QAAQ,SAAS,KAAG,SAAmB,CAAC"}
@@ -0,0 +1,65 @@
1
+ /** Reserved key under `registrations[ContractName]` for contract-level metadata (not an implementation). */
2
+ export const IOC_CONTRACT_CONFIG_KEY = "$contract";
3
+ export const parseContractLevelConfig = (entry, pathForError) => {
4
+ if (entry === undefined) {
5
+ return {};
6
+ }
7
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
8
+ throw new Error(`[ioc-config] ${pathForError} must be an object`);
9
+ }
10
+ const rec = entry;
11
+ for (const k of Object.keys(rec)) {
12
+ if (k !== "accessKey") {
13
+ throw new Error(`[ioc-config] ${pathForError} has unknown property ${JSON.stringify(k)} (only accessKey is allowed)`);
14
+ }
15
+ }
16
+ const accessKey = rec.accessKey;
17
+ if (accessKey === undefined) {
18
+ return {};
19
+ }
20
+ if (typeof accessKey !== "string" || accessKey.length === 0) {
21
+ throw new Error(`[ioc-config] ${pathForError}.accessKey must be a non-empty string when set`);
22
+ }
23
+ if (accessKey === IOC_CONTRACT_CONFIG_KEY) {
24
+ throw new Error(`[ioc-config] ${pathForError}.accessKey cannot be ${JSON.stringify(IOC_CONTRACT_CONFIG_KEY)} (reserved)`);
25
+ }
26
+ return { accessKey };
27
+ };
28
+ export const getContractLevelConfig = (perContract, contractLabel) => {
29
+ if (perContract === undefined) {
30
+ return {};
31
+ }
32
+ const raw = perContract[IOC_CONTRACT_CONFIG_KEY];
33
+ if (raw === undefined) {
34
+ return {};
35
+ }
36
+ return parseContractLevelConfig(raw, `registrations[${JSON.stringify(contractLabel)}][${JSON.stringify(IOC_CONTRACT_CONFIG_KEY)}]`);
37
+ };
38
+ /** True when the value is per-implementation config (not a misplaced `$contract` object). */
39
+ export const isIocImplementationOverride = (value) => {
40
+ if (typeof value !== "object" || value === null) {
41
+ return false;
42
+ }
43
+ if ("name" in value || "lifetime" in value || "default" in value) {
44
+ return true;
45
+ }
46
+ if ("accessKey" in value) {
47
+ return false;
48
+ }
49
+ return true;
50
+ };
51
+ export const getImplOverrideForImplementation = (perContract, implementationName) => {
52
+ if (perContract === undefined) {
53
+ return undefined;
54
+ }
55
+ if (implementationName === IOC_CONTRACT_CONFIG_KEY) {
56
+ return undefined;
57
+ }
58
+ const raw = perContract[implementationName];
59
+ if (raw === undefined || !isIocImplementationOverride(raw)) {
60
+ return undefined;
61
+ }
62
+ return raw;
63
+ };
64
+ export const defineIocConfig = (config) => config;
65
+ //# sourceMappingURL=iocConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iocConfig.js","sourceRoot":"","sources":["../../src/config/iocConfig.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type IocConfig } from "./iocConfig.js";
2
+ export declare const loadIocConfig: (absoluteConfigPath: string) => Promise<IocConfig>;
3
+ /**
4
+ * IoC package root inferred from where `ioc.config` lives: if the config file is under a `src`
5
+ * directory, the package root is the parent of that `src` (so `discovery.scanDirs` entries stay relative
6
+ * to the package, not `process.cwd()`). Otherwise the package root is the config file directory.
7
+ */
8
+ export declare const resolveProjectRootFromIocConfigPath: (absoluteConfigPath: string) => string;
9
+ /**
10
+ * Resolves the absolute path to `ioc.config.ts`.
11
+ *
12
+ * - When `explicitPath` or `IOC_CONFIG` is set, resolves relative to `searchStartDir` if not absolute.
13
+ * - Otherwise walks upward from `searchStartDir` for `src/ioc.config.ts` / `ioc.config.ts`.
14
+ * - If none is found upward, searches downward for the shallowest nested `src/ioc.config.ts`
15
+ * (glob, excluding `node_modules` and similar). If several are found, throws with a prompt to use
16
+ * `--project` / `--config`.
17
+ * - If still none, returns `searchStartDir/src/ioc.config.ts` (legacy default) for missing-file handling.
18
+ */
19
+ export declare const resolveIocConfigPath: (searchStartDir: string, explicitPath?: string) => string;
20
+ /**
21
+ * Returns `undefined` if the file is missing — used when generation should fall back to CLI defaults.
22
+ * If the file exists, loads it and validates (same as {@link loadIocConfig}).
23
+ */
24
+ export declare const tryLoadIocConfig: (absoluteConfigPath: string) => Promise<IocConfig | undefined>;
25
+ //# sourceMappingURL=loadIocConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadIocConfig.d.ts","sourceRoot":"","sources":["../../src/config/loadIocConfig.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,SAAS,EAEf,MAAM,gBAAgB,CAAC;AA0QxB,eAAO,MAAM,aAAa,GACxB,oBAAoB,MAAM,KACzB,OAAO,CAAC,SAAS,CAKnB,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,mCAAmC,GAC9C,oBAAoB,MAAM,KACzB,MAKF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAC/B,gBAAgB,MAAM,EACtB,eAAe,MAAM,KACpB,MAwDF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAC3B,oBAAoB,MAAM,KACzB,OAAO,CAAC,SAAS,GAAG,SAAS,CAQ/B,CAAC"}
@@ -0,0 +1,245 @@
1
+ /**
2
+ * @fileoverview Loads and validates `ioc.config.ts` (or `--config` / `IOC_CONFIG` overrides).
3
+ * Fail-fast validation with `[ioc-config]` errors. The loaded module’s default export (or
4
+ * `iocConfig` / `config`) supplies the raw shape validated into {@link IocConfig}.
5
+ */
6
+ import { existsSync } from "node:fs";
7
+ import fs from "node:fs/promises";
8
+ import path from "node:path";
9
+ import { pathToFileURL } from "node:url";
10
+ import fg from "fast-glob";
11
+ import { IOC_CONTRACT_CONFIG_KEY, parseContractLevelConfig, } from "./iocConfig.js";
12
+ import { parseDiscoveryScanDirs } from "./parseDiscoveryScanDirs.js";
13
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
14
+ const TOP_LEVEL_KEYS = new Set(["discovery", "registrations", "groups"]);
15
+ const DISCOVERY_KEYS = new Set([
16
+ "scanDirs",
17
+ "includes",
18
+ "excludes",
19
+ "factoryPrefix",
20
+ "generatedDir",
21
+ "workspacePackageImportBases",
22
+ ]);
23
+ const IMPL_OVERRIDE_KEYS = new Set(["name", "lifetime", "default"]);
24
+ const assertOnlyKeys = (record, allowed, pathLabel) => {
25
+ for (const k of Object.keys(record)) {
26
+ if (!allowed.has(k)) {
27
+ throw new Error(`[ioc-config] ${pathLabel} has unknown property ${JSON.stringify(k)}`);
28
+ }
29
+ }
30
+ };
31
+ const validateWorkspacePackageImportBases = (value, pathLabel) => {
32
+ if (value === undefined) {
33
+ return;
34
+ }
35
+ if (!Array.isArray(value)) {
36
+ throw new Error(`[ioc-config] ${pathLabel} must be an array when set`);
37
+ }
38
+ for (let i = 0; i < value.length; i += 1) {
39
+ const el = value[i];
40
+ if (!isRecord(el)) {
41
+ throw new Error(`[ioc-config] ${pathLabel}[${i}] must be an object`);
42
+ }
43
+ assertOnlyKeys(el, new Set(["root", "importBase"]), `${pathLabel}[${i}]`);
44
+ const root = el.root;
45
+ if (typeof root !== "string" || root.length === 0) {
46
+ throw new Error(`[ioc-config] ${pathLabel}[${i}].root must be a non-empty string`);
47
+ }
48
+ const importBase = el.importBase;
49
+ if (typeof importBase !== "string" || importBase.length === 0) {
50
+ throw new Error(`[ioc-config] ${pathLabel}[${i}].importBase must be a non-empty string`);
51
+ }
52
+ }
53
+ };
54
+ const GROUP_KINDS = new Set(["collection", "object"]);
55
+ const IOC_LIFETIMES = new Set(["singleton", "scoped", "transient"]);
56
+ const isIocLifetime = (value) => typeof value === "string" && IOC_LIFETIMES.has(value);
57
+ const validateGroupsShape = (value, pathLabel) => {
58
+ if (!isRecord(value)) {
59
+ throw new Error(`[ioc-config] ${pathLabel} must be an object`);
60
+ }
61
+ for (const [name, entry] of Object.entries(value)) {
62
+ if (!isRecord(entry)) {
63
+ throw new Error(`[ioc-config] ${pathLabel}.${JSON.stringify(name)} must be an object`);
64
+ }
65
+ const kind = entry.kind;
66
+ if (typeof kind !== "string" || !GROUP_KINDS.has(kind)) {
67
+ throw new Error(`[ioc-config] ${pathLabel}.${JSON.stringify(name)}.kind must be "collection" or "object"`);
68
+ }
69
+ const baseType = entry.baseType;
70
+ if (typeof baseType !== "string" || baseType.length === 0) {
71
+ throw new Error(`[ioc-config] ${pathLabel}.${JSON.stringify(name)}.baseType must be a non-empty string`);
72
+ }
73
+ const allowed = new Set(["kind", "baseType"]);
74
+ for (const key of Object.keys(entry)) {
75
+ if (!allowed.has(key)) {
76
+ throw new Error(`[ioc-config] ${pathLabel}.${JSON.stringify(name)} has unknown property ${JSON.stringify(key)} (only kind and baseType are allowed)`);
77
+ }
78
+ }
79
+ }
80
+ };
81
+ const validateStringArray = (value, pathLabel) => {
82
+ if (!Array.isArray(value) ||
83
+ !value.every((item) => typeof item === "string")) {
84
+ throw new Error(`[ioc-config] ${pathLabel} must be string[] when set`);
85
+ }
86
+ };
87
+ const validateOptionalNonEmptyString = (value, pathLabel) => {
88
+ if (value !== undefined &&
89
+ (typeof value !== "string" || value.length === 0)) {
90
+ throw new Error(`[ioc-config] ${pathLabel} must be a non-empty string when set`);
91
+ }
92
+ };
93
+ const validateRegistrationsShape = (registrations, sourceLabel) => {
94
+ if (registrations === undefined) {
95
+ return;
96
+ }
97
+ if (!isRecord(registrations)) {
98
+ throw new Error(`[ioc-config] ${sourceLabel} registrations must be an object`);
99
+ }
100
+ for (const [contractName, perImplementation] of Object.entries(registrations)) {
101
+ if (!isRecord(perImplementation)) {
102
+ throw new Error(`[ioc-config] ${sourceLabel} registrations["${contractName}"] must be an object`);
103
+ }
104
+ for (const [implementationName, override] of Object.entries(perImplementation)) {
105
+ if (!isRecord(override)) {
106
+ throw new Error(`[ioc-config] ${sourceLabel} registrations["${contractName}"]["${implementationName}"] must be an object`);
107
+ }
108
+ if (implementationName === IOC_CONTRACT_CONFIG_KEY) {
109
+ parseContractLevelConfig(override, `${sourceLabel} registrations["${contractName}"]["${implementationName}"]`);
110
+ continue;
111
+ }
112
+ assertOnlyKeys(override, IMPL_OVERRIDE_KEYS, `${sourceLabel} registrations["${contractName}"]["${implementationName}"]`);
113
+ if (override.name !== undefined) {
114
+ if (typeof override.name !== "string" || override.name.length === 0) {
115
+ throw new Error(`[ioc-config] ${sourceLabel} registrations["${contractName}"]["${implementationName}"].name must be a non-empty string when set`);
116
+ }
117
+ }
118
+ if (override.lifetime !== undefined &&
119
+ !isIocLifetime(override.lifetime)) {
120
+ throw new Error(`[ioc-config] ${sourceLabel} registrations["${contractName}"]["${implementationName}"].lifetime must be singleton | scoped | transient when set`);
121
+ }
122
+ if (override.default !== undefined &&
123
+ typeof override.default !== "boolean") {
124
+ throw new Error(`[ioc-config] ${sourceLabel} registrations["${contractName}"]["${implementationName}"].default must be a boolean when set`);
125
+ }
126
+ }
127
+ }
128
+ };
129
+ const validateIocConfig = (raw, sourceLabel) => {
130
+ if (!isRecord(raw)) {
131
+ throw new Error(`[ioc-config] ${sourceLabel} must export an object`);
132
+ }
133
+ assertOnlyKeys(raw, TOP_LEVEL_KEYS, sourceLabel);
134
+ const discovery = raw.discovery;
135
+ if (!isRecord(discovery)) {
136
+ throw new Error(`[ioc-config] ${sourceLabel} is missing discovery`);
137
+ }
138
+ assertOnlyKeys(discovery, DISCOVERY_KEYS, `${sourceLabel} discovery`);
139
+ parseDiscoveryScanDirs(discovery.scanDirs, `${sourceLabel} discovery.scanDirs`);
140
+ if (discovery.includes !== undefined) {
141
+ validateStringArray(discovery.includes, `${sourceLabel} discovery.includes`);
142
+ }
143
+ if (discovery.excludes !== undefined) {
144
+ validateStringArray(discovery.excludes, `${sourceLabel} discovery.excludes`);
145
+ }
146
+ validateOptionalNonEmptyString(discovery.factoryPrefix, `${sourceLabel} discovery.factoryPrefix`);
147
+ validateOptionalNonEmptyString(discovery.generatedDir, `${sourceLabel} discovery.generatedDir`);
148
+ validateWorkspacePackageImportBases(discovery.workspacePackageImportBases, `${sourceLabel} discovery.workspacePackageImportBases`);
149
+ validateRegistrationsShape(raw.registrations, sourceLabel);
150
+ if (raw.groups !== undefined) {
151
+ validateGroupsShape(raw.groups, `${sourceLabel} groups`);
152
+ }
153
+ return raw;
154
+ };
155
+ export const loadIocConfig = async (absoluteConfigPath) => {
156
+ const url = pathToFileURL(absoluteConfigPath).href;
157
+ const mod = await import(url);
158
+ const raw = mod.default ?? mod.iocConfig ?? mod.config;
159
+ return validateIocConfig(raw, absoluteConfigPath);
160
+ };
161
+ const CONFIG_RELATIVE_SEARCH_PATHS = ["src/ioc.config.ts", "ioc.config.ts"];
162
+ /**
163
+ * IoC package root inferred from where `ioc.config` lives: if the config file is under a `src`
164
+ * directory, the package root is the parent of that `src` (so `discovery.scanDirs` entries stay relative
165
+ * to the package, not `process.cwd()`). Otherwise the package root is the config file directory.
166
+ */
167
+ export const resolveProjectRootFromIocConfigPath = (absoluteConfigPath) => {
168
+ const configDir = path.dirname(absoluteConfigPath);
169
+ return path.basename(configDir) === "src"
170
+ ? path.dirname(configDir)
171
+ : configDir;
172
+ };
173
+ /**
174
+ * Resolves the absolute path to `ioc.config.ts`.
175
+ *
176
+ * - When `explicitPath` or `IOC_CONFIG` is set, resolves relative to `searchStartDir` if not absolute.
177
+ * - Otherwise walks upward from `searchStartDir` for `src/ioc.config.ts` / `ioc.config.ts`.
178
+ * - If none is found upward, searches downward for the shallowest nested `src/ioc.config.ts`
179
+ * (glob, excluding `node_modules` and similar). If several are found, throws with a prompt to use
180
+ * `--project` / `--config`.
181
+ * - If still none, returns `searchStartDir/src/ioc.config.ts` (legacy default) for missing-file handling.
182
+ */
183
+ export const resolveIocConfigPath = (searchStartDir, explicitPath) => {
184
+ const start = path.resolve(searchStartDir);
185
+ if (explicitPath !== undefined && explicitPath.length > 0) {
186
+ return path.isAbsolute(explicitPath)
187
+ ? explicitPath
188
+ : path.resolve(start, explicitPath);
189
+ }
190
+ const fromEnv = process.env.IOC_CONFIG;
191
+ if (typeof fromEnv === "string" && fromEnv.length > 0) {
192
+ return path.isAbsolute(fromEnv)
193
+ ? fromEnv
194
+ : path.resolve(start, fromEnv);
195
+ }
196
+ let dir = start;
197
+ const root = path.parse(dir).root;
198
+ while (true) {
199
+ for (const rel of CONFIG_RELATIVE_SEARCH_PATHS) {
200
+ const candidate = path.join(dir, rel);
201
+ if (existsSync(candidate)) {
202
+ return candidate;
203
+ }
204
+ }
205
+ if (dir === root) {
206
+ break;
207
+ }
208
+ dir = path.dirname(dir);
209
+ }
210
+ const downward = fg.sync("**/src/ioc.config.ts", {
211
+ cwd: start,
212
+ absolute: true,
213
+ onlyFiles: true,
214
+ unique: true,
215
+ deep: 15,
216
+ ignore: [
217
+ "**/node_modules/**",
218
+ "**/dist/**",
219
+ "**/.git/**",
220
+ ],
221
+ });
222
+ const byPathDepth = (a, b) => a.split(path.sep).length - b.split(path.sep).length;
223
+ const ranked = [...new Set(downward)].sort(byPathDepth);
224
+ if (ranked.length === 1) {
225
+ return ranked[0];
226
+ }
227
+ if (ranked.length > 1) {
228
+ throw new Error(`[ioc-config] Multiple src/ioc.config.ts files found under ${start}. Pass --project <path> to the package directory or use --config.`);
229
+ }
230
+ return path.join(start, "src", "ioc.config.ts");
231
+ };
232
+ /**
233
+ * Returns `undefined` if the file is missing — used when generation should fall back to CLI defaults.
234
+ * If the file exists, loads it and validates (same as {@link loadIocConfig}).
235
+ */
236
+ export const tryLoadIocConfig = async (absoluteConfigPath) => {
237
+ try {
238
+ await fs.access(absoluteConfigPath);
239
+ }
240
+ catch {
241
+ return undefined;
242
+ }
243
+ return loadIocConfig(absoluteConfigPath);
244
+ };
245
+ //# sourceMappingURL=loadIocConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadIocConfig.js","sourceRoot":"","sources":["../../src/config/loadIocConfig.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { IocScanDirSpec } from "./iocConfig.js";
2
+ /**
3
+ * Validates and normalizes authoring `scanDirs` into a list of specs (single string → one spec).
4
+ */
5
+ export declare const parseDiscoveryScanDirs: (raw: unknown, sourceLabel: string) => IocScanDirSpec[];
6
+ //# sourceMappingURL=parseDiscoveryScanDirs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseDiscoveryScanDirs.d.ts","sourceRoot":"","sources":["../../src/config/parseDiscoveryScanDirs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAOlE;;GAEG;AACH,eAAO,MAAM,sBAAsB,GACjC,KAAK,OAAO,EACZ,aAAa,MAAM,KAClB,cAAc,EAsGhB,CAAC"}
@@ -0,0 +1,78 @@
1
+ const IOC_LIFETIMES = new Set(["singleton", "scoped", "transient"]);
2
+ const isIocLifetime = (value) => typeof value === "string" && IOC_LIFETIMES.has(value);
3
+ /**
4
+ * Validates and normalizes authoring `scanDirs` into a list of specs (single string → one spec).
5
+ */
6
+ export const parseDiscoveryScanDirs = (raw, sourceLabel) => {
7
+ if (typeof raw === "string") {
8
+ if (raw.length === 0) {
9
+ throw new Error(`[ioc-config] ${sourceLabel} discovery.scanDirs must be a non-empty string when a string is used`);
10
+ }
11
+ return [{ path: raw }];
12
+ }
13
+ if (!Array.isArray(raw) || raw.length === 0) {
14
+ throw new Error(`[ioc-config] ${sourceLabel} discovery.scanDirs must be a non-empty string, string[], or object[]`);
15
+ }
16
+ const out = [];
17
+ const allowedKeys = new Set(["path", "importPrefix", "importMode", "scope"]);
18
+ for (let i = 0; i < raw.length; i += 1) {
19
+ const el = raw[i];
20
+ if (typeof el === "string") {
21
+ if (el.length === 0) {
22
+ throw new Error(`[ioc-config] ${sourceLabel} discovery.scanDirs[${i}] must be a non-empty string`);
23
+ }
24
+ out.push({ path: el });
25
+ continue;
26
+ }
27
+ if (typeof el !== "object" || el === null || Array.isArray(el)) {
28
+ throw new Error(`[ioc-config] ${sourceLabel} discovery.scanDirs[${i}] must be a string or an object with path`);
29
+ }
30
+ const rec = el;
31
+ for (const k of Object.keys(rec)) {
32
+ if (!allowedKeys.has(k)) {
33
+ throw new Error(`[ioc-config] ${sourceLabel} discovery.scanDirs[${i}] has unknown property ${JSON.stringify(k)}`);
34
+ }
35
+ }
36
+ const p = rec.path;
37
+ if (typeof p !== "string" || p.length === 0) {
38
+ throw new Error(`[ioc-config] ${sourceLabel} discovery.scanDirs[${i}].path must be a non-empty string`);
39
+ }
40
+ const importPrefix = rec.importPrefix;
41
+ if (importPrefix !== undefined) {
42
+ if (typeof importPrefix !== "string" || importPrefix.length === 0) {
43
+ throw new Error(`[ioc-config] ${sourceLabel} discovery.scanDirs[${i}].importPrefix must be a non-empty string when set`);
44
+ }
45
+ }
46
+ const importMode = rec.importMode;
47
+ const scopeRaw = rec.scope;
48
+ let scope;
49
+ if (scopeRaw !== undefined) {
50
+ if (!isIocLifetime(scopeRaw)) {
51
+ throw new Error(`[ioc-config] ${sourceLabel} discovery.scanDirs[${i}].scope must be singleton | scoped | transient when set`);
52
+ }
53
+ scope = scopeRaw;
54
+ }
55
+ if (importPrefix !== undefined) {
56
+ if (importMode !== "root" && importMode !== "subpath") {
57
+ throw new Error(`[ioc-config] ${sourceLabel} discovery.scanDirs[${i}].importMode must be "root" or "subpath" when importPrefix is set`);
58
+ }
59
+ out.push({
60
+ path: p,
61
+ importPrefix,
62
+ importMode,
63
+ ...(scope !== undefined ? { scope } : {}),
64
+ });
65
+ }
66
+ else {
67
+ if (importMode === "root") {
68
+ throw new Error(`[ioc-config] ${sourceLabel} discovery.scanDirs[${i}].importMode cannot be set to "root" without importPrefix`);
69
+ }
70
+ out.push({
71
+ path: p,
72
+ ...(scope !== undefined ? { scope } : {}),
73
+ });
74
+ }
75
+ }
76
+ return out;
77
+ };
78
+ //# sourceMappingURL=parseDiscoveryScanDirs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseDiscoveryScanDirs.js","sourceRoot":"","sources":["../../src/config/parseDiscoveryScanDirs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export type ContractDefaultSelectionRow = {
2
+ readonly implementationName: string;
3
+ readonly registrationKey: string;
4
+ readonly default?: boolean;
5
+ };
6
+ /**
7
+ * Resolves which implementation backs the contract default slot. Precedence:
8
+ * 1. Exactly one row with `default: true`
9
+ * 2. Exactly one row whose `registrationKey` equals the contract key (camel-cased contract name)
10
+ * 3. Exactly one row total
11
+ * 4. Otherwise throws (ambiguous)
12
+ */
13
+ export declare const selectDefaultImplementationName: (contractName: string, rows: readonly ContractDefaultSelectionRow[]) => string;
14
+ //# sourceMappingURL=defaultImplementationSelection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaultImplementationSelection.d.ts","sourceRoot":"","sources":["../../src/core/defaultImplementationSelection.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,+BAA+B,GAC1C,cAAc,MAAM,EACpB,MAAM,SAAS,2BAA2B,EAAE,KAC3C,MAkDF,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { contractNameToDefaultRegistrationKey } from "../generator/naming.js";
2
+ /**
3
+ * Resolves which implementation backs the contract default slot. Precedence:
4
+ * 1. Exactly one row with `default: true`
5
+ * 2. Exactly one row whose `registrationKey` equals the contract key (camel-cased contract name)
6
+ * 3. Exactly one row total
7
+ * 4. Otherwise throws (ambiguous)
8
+ */
9
+ export const selectDefaultImplementationName = (contractName, rows) => {
10
+ if (rows.length === 0) {
11
+ throw new Error(`[ioc] Contract ${JSON.stringify(contractName)} has no implementations.`);
12
+ }
13
+ const withDefault = rows.filter((r) => r.default === true);
14
+ if (withDefault.length > 1) {
15
+ const names = withDefault
16
+ .map((r) => r.implementationName)
17
+ .sort((a, b) => a.localeCompare(b))
18
+ .map((n) => JSON.stringify(n))
19
+ .join(", ");
20
+ throw new Error(`[ioc] Contract ${JSON.stringify(contractName)} has multiple implementations marked default: true after applying ioc.config overrides: ${names}. Mark exactly one with default: true in source or in registrations[${JSON.stringify(contractName)}][implementationName], or reduce to a single implementation.`);
21
+ }
22
+ if (withDefault.length === 1) {
23
+ return withDefault[0].implementationName;
24
+ }
25
+ const contractKey = contractNameToDefaultRegistrationKey(contractName);
26
+ const conventionMatches = rows.filter((r) => r.registrationKey === contractKey);
27
+ if (conventionMatches.length > 1) {
28
+ throw new Error(`[ioc] Contract ${JSON.stringify(contractName)} has multiple implementations registered under the contract key ${JSON.stringify(contractKey)}.`);
29
+ }
30
+ if (conventionMatches.length === 1) {
31
+ return conventionMatches[0].implementationName;
32
+ }
33
+ if (rows.length === 1) {
34
+ return rows[0].implementationName;
35
+ }
36
+ const names = rows
37
+ .map((r) => r.implementationName)
38
+ .sort((a, b) => a.localeCompare(b))
39
+ .map((n) => JSON.stringify(n))
40
+ .join(", ");
41
+ const keys = rows
42
+ .map((r) => `${r.implementationName}→${JSON.stringify(r.registrationKey)}`)
43
+ .sort((a, b) => a.localeCompare(b))
44
+ .join(", ");
45
+ throw new Error(`[ioc] Contract ${JSON.stringify(contractName)} has ${rows.length} implementations (${names}) but none is selected as the default. Set registrations[${JSON.stringify(contractName)}][implementationName].default: true in ioc.config.ts for exactly one implementation, mark exactly one factory with resolver default: true, register exactly one implementation under the contract key ${JSON.stringify(contractKey)}, or reduce to a single implementation. Registration keys: ${keys}.`);
46
+ };
47
+ //# sourceMappingURL=defaultImplementationSelection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaultImplementationSelection.js","sourceRoot":"","sources":["../../src/core/defaultImplementationSelection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oCAAoC,EAAE,MAAM,wBAAwB,CAAC;AAQ9E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC7C,YAAoB,EACpB,IAA4C,EACpC,EAAE;IACV,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,kBAAkB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,0BAA0B,CACzE,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC;IAC3D,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,WAAW;aACtB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC;aAChC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;aAClC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;aAC7B,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,IAAI,KAAK,CACb,kBAAkB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,2FAA2F,KAAK,uEAAuE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,8DAA8D,CAChT,CAAC;IACJ,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,WAAW,CAAC,CAAC,CAAE,CAAC,kBAAkB,CAAC;IAC5C,CAAC;IAED,MAAM,WAAW,GAAG,oCAAoC,CAAC,YAAY,CAAC,CAAC;IACvE,MAAM,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,WAAW,CAAC,CAAC;IAChF,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,kBAAkB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,mEAAmE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,CAChJ,CAAC;IACJ,CAAC;IACD,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO,iBAAiB,CAAC,CAAC,CAAE,CAAC,kBAAkB,CAAC;IAClD,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC,CAAC,CAAE,CAAC,kBAAkB,CAAC;IACrC,CAAC;IAED,MAAM,KAAK,GAAG,IAAI;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC;SAChC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;SAClC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;SAC7B,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,IAAI,GAAG,IAAI;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,kBAAkB,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC;SAC1E,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;SAClC,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,IAAI,KAAK,CACb,kBAAkB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,QAAQ,IAAI,CAAC,MAAM,qBAAqB,KAAK,4DAA4D,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,yMAAyM,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,8DAA8D,IAAI,GAAG,CAC7d,CAAC;AACJ,CAAC,CAAC"}