@gqlkit-ts/cli 0.0.1 → 0.1.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 (325) hide show
  1. package/LICENSE +21 -0
  2. package/dist/auto-type-generator/auto-type-generator.d.ts +46 -0
  3. package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -0
  4. package/dist/auto-type-generator/auto-type-generator.js +353 -0
  5. package/dist/auto-type-generator/auto-type-generator.js.map +1 -0
  6. package/dist/auto-type-generator/auto-type-generator.test.d.ts +2 -0
  7. package/dist/auto-type-generator/auto-type-generator.test.d.ts.map +1 -0
  8. package/dist/auto-type-generator/auto-type-generator.test.js +613 -0
  9. package/dist/auto-type-generator/auto-type-generator.test.js.map +1 -0
  10. package/dist/auto-type-generator/index.d.ts +4 -0
  11. package/dist/auto-type-generator/index.d.ts.map +1 -0
  12. package/dist/auto-type-generator/index.js +3 -0
  13. package/dist/auto-type-generator/index.js.map +1 -0
  14. package/dist/auto-type-generator/name-collision-validator.d.ts +17 -0
  15. package/dist/auto-type-generator/name-collision-validator.d.ts.map +1 -0
  16. package/dist/auto-type-generator/name-collision-validator.js +68 -0
  17. package/dist/auto-type-generator/name-collision-validator.js.map +1 -0
  18. package/dist/auto-type-generator/name-collision-validator.test.d.ts +2 -0
  19. package/dist/auto-type-generator/name-collision-validator.test.d.ts.map +1 -0
  20. package/dist/auto-type-generator/name-collision-validator.test.js +358 -0
  21. package/dist/auto-type-generator/name-collision-validator.test.js.map +1 -0
  22. package/dist/auto-type-generator/naming-convention.d.ts +40 -0
  23. package/dist/auto-type-generator/naming-convention.d.ts.map +1 -0
  24. package/dist/auto-type-generator/naming-convention.js +59 -0
  25. package/dist/auto-type-generator/naming-convention.js.map +1 -0
  26. package/dist/auto-type-generator/naming-convention.test.d.ts +2 -0
  27. package/dist/auto-type-generator/naming-convention.test.d.ts.map +1 -0
  28. package/dist/auto-type-generator/naming-convention.test.js +132 -0
  29. package/dist/auto-type-generator/naming-convention.test.js.map +1 -0
  30. package/dist/cli.d.ts +2 -0
  31. package/dist/cli.d.ts.map +1 -0
  32. package/dist/cli.js +11 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/commands/gen.d.ts +32 -0
  35. package/dist/commands/gen.d.ts.map +1 -0
  36. package/dist/commands/gen.js +101 -0
  37. package/dist/commands/gen.js.map +1 -0
  38. package/dist/commands/gen.test.d.ts +2 -0
  39. package/dist/commands/gen.test.d.ts.map +1 -0
  40. package/dist/commands/gen.test.js +226 -0
  41. package/dist/commands/gen.test.js.map +1 -0
  42. package/dist/commands/main.d.ts +12 -0
  43. package/dist/commands/main.d.ts.map +1 -0
  44. package/dist/commands/main.js +5 -0
  45. package/dist/commands/main.js.map +1 -0
  46. package/dist/config/define-config.d.ts +26 -0
  47. package/dist/config/define-config.d.ts.map +1 -0
  48. package/dist/config/define-config.js +27 -0
  49. package/dist/config/define-config.js.map +1 -0
  50. package/dist/config/index.d.ts +3 -0
  51. package/dist/config/index.d.ts.map +1 -0
  52. package/dist/config/index.js +2 -0
  53. package/dist/config/index.js.map +1 -0
  54. package/dist/config/types.d.ts +131 -0
  55. package/dist/config/types.d.ts.map +1 -0
  56. package/dist/config/types.js +2 -0
  57. package/dist/config/types.js.map +1 -0
  58. package/dist/config-loader/index.d.ts +3 -0
  59. package/dist/config-loader/index.d.ts.map +1 -0
  60. package/dist/config-loader/index.js +2 -0
  61. package/dist/config-loader/index.js.map +1 -0
  62. package/dist/config-loader/loader.d.ts +50 -0
  63. package/dist/config-loader/loader.d.ts.map +1 -0
  64. package/dist/config-loader/loader.js +78 -0
  65. package/dist/config-loader/loader.js.map +1 -0
  66. package/dist/config-loader/loader.test.d.ts +2 -0
  67. package/dist/config-loader/loader.test.d.ts.map +1 -0
  68. package/dist/config-loader/loader.test.js +123 -0
  69. package/dist/config-loader/loader.test.js.map +1 -0
  70. package/dist/config-loader/validator.d.ts +13 -0
  71. package/dist/config-loader/validator.d.ts.map +1 -0
  72. package/dist/config-loader/validator.js +497 -0
  73. package/dist/config-loader/validator.js.map +1 -0
  74. package/dist/config-loader/validator.test.d.ts +2 -0
  75. package/dist/config-loader/validator.test.d.ts.map +1 -0
  76. package/dist/config-loader/validator.test.js +846 -0
  77. package/dist/config-loader/validator.test.js.map +1 -0
  78. package/dist/gen-orchestrator/golden.test.d.ts +2 -0
  79. package/dist/gen-orchestrator/golden.test.d.ts.map +1 -0
  80. package/dist/gen-orchestrator/golden.test.js +102 -0
  81. package/dist/gen-orchestrator/golden.test.js.map +1 -0
  82. package/dist/gen-orchestrator/hook-executor/hook-executor.d.ts +25 -0
  83. package/dist/gen-orchestrator/hook-executor/hook-executor.d.ts.map +1 -0
  84. package/dist/gen-orchestrator/hook-executor/hook-executor.js +68 -0
  85. package/dist/gen-orchestrator/hook-executor/hook-executor.js.map +1 -0
  86. package/dist/gen-orchestrator/hook-executor/hook-executor.test.d.ts +2 -0
  87. package/dist/gen-orchestrator/hook-executor/hook-executor.test.d.ts.map +1 -0
  88. package/dist/gen-orchestrator/hook-executor/hook-executor.test.js +167 -0
  89. package/dist/gen-orchestrator/hook-executor/hook-executor.test.js.map +1 -0
  90. package/dist/gen-orchestrator/orchestrator.d.ts +30 -0
  91. package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -0
  92. package/dist/gen-orchestrator/orchestrator.js +407 -0
  93. package/dist/gen-orchestrator/orchestrator.js.map +1 -0
  94. package/dist/gen-orchestrator/reporter/diagnostic-reporter.d.ts +9 -0
  95. package/dist/gen-orchestrator/reporter/diagnostic-reporter.d.ts.map +1 -0
  96. package/dist/gen-orchestrator/reporter/diagnostic-reporter.js +32 -0
  97. package/dist/gen-orchestrator/reporter/diagnostic-reporter.js.map +1 -0
  98. package/dist/gen-orchestrator/reporter/progress-reporter.d.ts +19 -0
  99. package/dist/gen-orchestrator/reporter/progress-reporter.d.ts.map +1 -0
  100. package/dist/gen-orchestrator/reporter/progress-reporter.js +38 -0
  101. package/dist/gen-orchestrator/reporter/progress-reporter.js.map +1 -0
  102. package/dist/gen-orchestrator/reporter/progress-reporter.test.d.ts +2 -0
  103. package/dist/gen-orchestrator/reporter/progress-reporter.test.d.ts.map +1 -0
  104. package/dist/gen-orchestrator/reporter/progress-reporter.test.js +74 -0
  105. package/dist/gen-orchestrator/reporter/progress-reporter.test.js.map +1 -0
  106. package/dist/gen-orchestrator/writer/file-writer.d.ts +13 -0
  107. package/dist/gen-orchestrator/writer/file-writer.d.ts.map +1 -0
  108. package/dist/gen-orchestrator/writer/file-writer.js +22 -0
  109. package/dist/gen-orchestrator/writer/file-writer.js.map +1 -0
  110. package/dist/index.d.ts +3 -0
  111. package/dist/index.d.ts.map +1 -0
  112. package/dist/index.js +2 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/resolver-extractor/extract-resolvers.d.ts +40 -0
  115. package/dist/resolver-extractor/extract-resolvers.d.ts.map +1 -0
  116. package/dist/resolver-extractor/extract-resolvers.js +2 -0
  117. package/dist/resolver-extractor/extract-resolvers.js.map +1 -0
  118. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts +50 -0
  119. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -0
  120. package/dist/resolver-extractor/extractor/define-api-extractor.js +685 -0
  121. package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -0
  122. package/dist/resolver-extractor/index.d.ts +5 -0
  123. package/dist/resolver-extractor/index.d.ts.map +1 -0
  124. package/dist/resolver-extractor/index.js +2 -0
  125. package/dist/resolver-extractor/index.js.map +1 -0
  126. package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +25 -0
  127. package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -0
  128. package/dist/resolver-extractor/validator/abstract-resolver-validator.js +172 -0
  129. package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -0
  130. package/dist/resolver-extractor/validator/only-validator.d.ts +61 -0
  131. package/dist/resolver-extractor/validator/only-validator.d.ts.map +1 -0
  132. package/dist/resolver-extractor/validator/only-validator.js +76 -0
  133. package/dist/resolver-extractor/validator/only-validator.js.map +1 -0
  134. package/dist/resolver-extractor/validator/only-validator.test.d.ts +8 -0
  135. package/dist/resolver-extractor/validator/only-validator.test.d.ts.map +1 -0
  136. package/dist/resolver-extractor/validator/only-validator.test.js +352 -0
  137. package/dist/resolver-extractor/validator/only-validator.test.js.map +1 -0
  138. package/dist/schema-generator/builder/ast-builder.d.ts +7 -0
  139. package/dist/schema-generator/builder/ast-builder.d.ts.map +1 -0
  140. package/dist/schema-generator/builder/ast-builder.js +417 -0
  141. package/dist/schema-generator/builder/ast-builder.js.map +1 -0
  142. package/dist/schema-generator/builder/ast-builder.test.d.ts +2 -0
  143. package/dist/schema-generator/builder/ast-builder.test.d.ts.map +1 -0
  144. package/dist/schema-generator/builder/ast-builder.test.js +469 -0
  145. package/dist/schema-generator/builder/ast-builder.test.js.map +1 -0
  146. package/dist/schema-generator/emitter/code-emitter.d.ts +7 -0
  147. package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -0
  148. package/dist/schema-generator/emitter/code-emitter.js +201 -0
  149. package/dist/schema-generator/emitter/code-emitter.js.map +1 -0
  150. package/dist/schema-generator/emitter/sdl-emitter.d.ts +7 -0
  151. package/dist/schema-generator/emitter/sdl-emitter.d.ts.map +1 -0
  152. package/dist/schema-generator/emitter/sdl-emitter.js +11 -0
  153. package/dist/schema-generator/emitter/sdl-emitter.js.map +1 -0
  154. package/dist/schema-generator/generate-schema.d.ts +26 -0
  155. package/dist/schema-generator/generate-schema.d.ts.map +1 -0
  156. package/dist/schema-generator/generate-schema.js +76 -0
  157. package/dist/schema-generator/generate-schema.js.map +1 -0
  158. package/dist/schema-generator/index.d.ts +4 -0
  159. package/dist/schema-generator/index.d.ts.map +1 -0
  160. package/dist/schema-generator/index.js +2 -0
  161. package/dist/schema-generator/index.js.map +1 -0
  162. package/dist/schema-generator/integrator/result-integrator.d.ts +93 -0
  163. package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -0
  164. package/dist/schema-generator/integrator/result-integrator.js +396 -0
  165. package/dist/schema-generator/integrator/result-integrator.js.map +1 -0
  166. package/dist/schema-generator/pruner/schema-pruner.d.ts +16 -0
  167. package/dist/schema-generator/pruner/schema-pruner.d.ts.map +1 -0
  168. package/dist/schema-generator/pruner/schema-pruner.js +66 -0
  169. package/dist/schema-generator/pruner/schema-pruner.js.map +1 -0
  170. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +24 -0
  171. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -0
  172. package/dist/schema-generator/resolver-collector/resolver-collector.js +61 -0
  173. package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -0
  174. package/dist/shared/constants.d.ts +70 -0
  175. package/dist/shared/constants.d.ts.map +1 -0
  176. package/dist/shared/constants.js +128 -0
  177. package/dist/shared/constants.js.map +1 -0
  178. package/dist/shared/default-value-detector.d.ts +40 -0
  179. package/dist/shared/default-value-detector.d.ts.map +1 -0
  180. package/dist/shared/default-value-detector.js +124 -0
  181. package/dist/shared/default-value-detector.js.map +1 -0
  182. package/dist/shared/diagnostics.d.ts +4 -0
  183. package/dist/shared/diagnostics.d.ts.map +1 -0
  184. package/dist/shared/diagnostics.js +25 -0
  185. package/dist/shared/diagnostics.js.map +1 -0
  186. package/dist/shared/directive-definition-extractor.d.ts +64 -0
  187. package/dist/shared/directive-definition-extractor.d.ts.map +1 -0
  188. package/dist/shared/directive-definition-extractor.js +399 -0
  189. package/dist/shared/directive-definition-extractor.js.map +1 -0
  190. package/dist/shared/directive-detector.d.ts +102 -0
  191. package/dist/shared/directive-detector.d.ts.map +1 -0
  192. package/dist/shared/directive-detector.js +422 -0
  193. package/dist/shared/directive-detector.js.map +1 -0
  194. package/dist/shared/file-scanner.d.ts +25 -0
  195. package/dist/shared/file-scanner.d.ts.map +1 -0
  196. package/dist/shared/file-scanner.js +99 -0
  197. package/dist/shared/file-scanner.js.map +1 -0
  198. package/dist/shared/file-scanner.test.d.ts +2 -0
  199. package/dist/shared/file-scanner.test.d.ts.map +1 -0
  200. package/dist/shared/file-scanner.test.js +138 -0
  201. package/dist/shared/file-scanner.test.js.map +1 -0
  202. package/dist/shared/index.d.ts +10 -0
  203. package/dist/shared/index.d.ts.map +1 -0
  204. package/dist/shared/index.js +8 -0
  205. package/dist/shared/index.js.map +1 -0
  206. package/dist/shared/inline-object-extractor.d.ts +13 -0
  207. package/dist/shared/inline-object-extractor.d.ts.map +1 -0
  208. package/dist/shared/inline-object-extractor.js +65 -0
  209. package/dist/shared/inline-object-extractor.js.map +1 -0
  210. package/dist/shared/inline-object-utils.d.ts +7 -0
  211. package/dist/shared/inline-object-utils.d.ts.map +1 -0
  212. package/dist/shared/inline-object-utils.js +23 -0
  213. package/dist/shared/inline-object-utils.js.map +1 -0
  214. package/dist/shared/interface-detector.d.ts +22 -0
  215. package/dist/shared/interface-detector.d.ts.map +1 -0
  216. package/dist/shared/interface-detector.js +90 -0
  217. package/dist/shared/interface-detector.js.map +1 -0
  218. package/dist/shared/interface-validator.d.ts +9 -0
  219. package/dist/shared/interface-validator.d.ts.map +1 -0
  220. package/dist/shared/interface-validator.js +152 -0
  221. package/dist/shared/interface-validator.js.map +1 -0
  222. package/dist/shared/interface-validator.test.d.ts +2 -0
  223. package/dist/shared/interface-validator.test.d.ts.map +1 -0
  224. package/dist/shared/interface-validator.test.js +145 -0
  225. package/dist/shared/interface-validator.test.js.map +1 -0
  226. package/dist/shared/metadata-detector.d.ts +65 -0
  227. package/dist/shared/metadata-detector.d.ts.map +1 -0
  228. package/dist/shared/metadata-detector.js +333 -0
  229. package/dist/shared/metadata-detector.js.map +1 -0
  230. package/dist/shared/program-factory.d.ts +14 -0
  231. package/dist/shared/program-factory.d.ts.map +1 -0
  232. package/dist/shared/program-factory.js +29 -0
  233. package/dist/shared/program-factory.js.map +1 -0
  234. package/dist/shared/source-location.d.ts +11 -0
  235. package/dist/shared/source-location.d.ts.map +1 -0
  236. package/dist/shared/source-location.js +15 -0
  237. package/dist/shared/source-location.js.map +1 -0
  238. package/dist/shared/tsconfig-loader.d.ts +13 -0
  239. package/dist/shared/tsconfig-loader.d.ts.map +1 -0
  240. package/dist/shared/tsconfig-loader.js +90 -0
  241. package/dist/shared/tsconfig-loader.js.map +1 -0
  242. package/dist/shared/tsdoc-parser.d.ts +12 -0
  243. package/dist/shared/tsdoc-parser.d.ts.map +1 -0
  244. package/dist/shared/tsdoc-parser.js +101 -0
  245. package/dist/shared/tsdoc-parser.js.map +1 -0
  246. package/dist/shared/type-converter.d.ts +3 -0
  247. package/dist/shared/type-converter.d.ts.map +1 -0
  248. package/dist/shared/type-converter.js +72 -0
  249. package/dist/shared/type-converter.js.map +1 -0
  250. package/dist/shared/typescript-utils.d.ts +55 -0
  251. package/dist/shared/typescript-utils.d.ts.map +1 -0
  252. package/dist/shared/typescript-utils.js +149 -0
  253. package/dist/shared/typescript-utils.js.map +1 -0
  254. package/dist/type-extractor/collector/result-collector.d.ts +7 -0
  255. package/dist/type-extractor/collector/result-collector.d.ts.map +1 -0
  256. package/dist/type-extractor/collector/result-collector.js +35 -0
  257. package/dist/type-extractor/collector/result-collector.js.map +1 -0
  258. package/dist/type-extractor/collector/scalar-collector.d.ts +108 -0
  259. package/dist/type-extractor/collector/scalar-collector.d.ts.map +1 -0
  260. package/dist/type-extractor/collector/scalar-collector.js +133 -0
  261. package/dist/type-extractor/collector/scalar-collector.js.map +1 -0
  262. package/dist/type-extractor/converter/field-eligibility.d.ts +34 -0
  263. package/dist/type-extractor/converter/field-eligibility.d.ts.map +1 -0
  264. package/dist/type-extractor/converter/field-eligibility.js +89 -0
  265. package/dist/type-extractor/converter/field-eligibility.js.map +1 -0
  266. package/dist/type-extractor/converter/graphql-converter.d.ts +7 -0
  267. package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -0
  268. package/dist/type-extractor/converter/graphql-converter.js +299 -0
  269. package/dist/type-extractor/converter/graphql-converter.js.map +1 -0
  270. package/dist/type-extractor/extract-types.d.ts +2 -0
  271. package/dist/type-extractor/extract-types.d.ts.map +1 -0
  272. package/dist/type-extractor/extract-types.js +2 -0
  273. package/dist/type-extractor/extract-types.js.map +1 -0
  274. package/dist/type-extractor/extractor/type-extractor.d.ts +27 -0
  275. package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -0
  276. package/dist/type-extractor/extractor/type-extractor.js +1116 -0
  277. package/dist/type-extractor/extractor/type-extractor.js.map +1 -0
  278. package/dist/type-extractor/index.d.ts +4 -0
  279. package/dist/type-extractor/index.d.ts.map +1 -0
  280. package/dist/type-extractor/index.js +2 -0
  281. package/dist/type-extractor/index.js.map +1 -0
  282. package/dist/type-extractor/types/diagnostics.d.ts +17 -0
  283. package/dist/type-extractor/types/diagnostics.d.ts.map +1 -0
  284. package/dist/type-extractor/types/diagnostics.js +2 -0
  285. package/dist/type-extractor/types/diagnostics.js.map +1 -0
  286. package/dist/type-extractor/types/graphql.d.ts +40 -0
  287. package/dist/type-extractor/types/graphql.d.ts.map +1 -0
  288. package/dist/type-extractor/types/graphql.js +2 -0
  289. package/dist/type-extractor/types/graphql.js.map +1 -0
  290. package/dist/type-extractor/types/index.d.ts +5 -0
  291. package/dist/type-extractor/types/index.d.ts.map +1 -0
  292. package/dist/type-extractor/types/index.js +2 -0
  293. package/dist/type-extractor/types/index.js.map +1 -0
  294. package/dist/type-extractor/types/typescript.d.ts +86 -0
  295. package/dist/type-extractor/types/typescript.d.ts.map +1 -0
  296. package/dist/type-extractor/types/typescript.js +2 -0
  297. package/dist/type-extractor/types/typescript.js.map +1 -0
  298. package/dist/type-extractor/types/typescript.test.d.ts +2 -0
  299. package/dist/type-extractor/types/typescript.test.d.ts.map +1 -0
  300. package/dist/type-extractor/types/typescript.test.js +287 -0
  301. package/dist/type-extractor/types/typescript.test.js.map +1 -0
  302. package/dist/type-extractor/validator/type-validator.d.ts +11 -0
  303. package/dist/type-extractor/validator/type-validator.d.ts.map +1 -0
  304. package/dist/type-extractor/validator/type-validator.js +53 -0
  305. package/dist/type-extractor/validator/type-validator.js.map +1 -0
  306. package/docs/configuration.md +163 -0
  307. package/docs/getting-started.md +117 -0
  308. package/docs/index.md +32 -0
  309. package/docs/integration/apollo.md +109 -0
  310. package/docs/integration/yoga.md +108 -0
  311. package/docs/schema/abstract-resolvers.md +146 -0
  312. package/docs/schema/directives.md +196 -0
  313. package/docs/schema/documentation.md +176 -0
  314. package/docs/schema/enums.md +162 -0
  315. package/docs/schema/fields.md +184 -0
  316. package/docs/schema/index.md +38 -0
  317. package/docs/schema/inputs.md +277 -0
  318. package/docs/schema/interfaces.md +178 -0
  319. package/docs/schema/objects.md +186 -0
  320. package/docs/schema/queries-mutations.md +205 -0
  321. package/docs/schema/scalars.md +194 -0
  322. package/docs/schema/unions.md +90 -0
  323. package/docs/what-is-gqlkit.md +22 -0
  324. package/package.json +59 -7
  325. package/README.md +0 -45
@@ -0,0 +1,846 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { validateConfig } from "./validator.js";
3
+ describe("ConfigValidator", () => {
4
+ const configPath = "/project/gqlkit.config.ts";
5
+ describe("validateConfig", () => {
6
+ it("should return valid for empty config", () => {
7
+ const result = validateConfig({
8
+ config: {},
9
+ configPath,
10
+ });
11
+ expect(result.valid).toBe(true);
12
+ expect(result.resolvedConfig).toBeTruthy();
13
+ expect(result.resolvedConfig.scalars).toEqual([]);
14
+ expect(result.diagnostics.length).toBe(0);
15
+ });
16
+ it("should return valid for config with scalars", () => {
17
+ const result = validateConfig({
18
+ config: {
19
+ scalars: [
20
+ {
21
+ graphqlName: "DateTime",
22
+ type: { from: "./src/scalars", name: "DateTime" },
23
+ },
24
+ ],
25
+ },
26
+ configPath,
27
+ });
28
+ expect(result.valid).toBe(true);
29
+ expect(result.resolvedConfig).toBeTruthy();
30
+ expect(result.resolvedConfig.scalars.length).toBe(1);
31
+ });
32
+ it("should return error for non-object config", () => {
33
+ const result = validateConfig({
34
+ config: "not an object",
35
+ configPath,
36
+ });
37
+ expect(result.valid).toBe(false);
38
+ expect(result.diagnostics.length).toBe(1);
39
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_TYPE");
40
+ });
41
+ it("should return error for null config", () => {
42
+ const result = validateConfig({
43
+ config: null,
44
+ configPath,
45
+ });
46
+ expect(result.valid).toBe(false);
47
+ expect(result.diagnostics.length).toBe(1);
48
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_TYPE");
49
+ });
50
+ it("should return error when scalars is not an array", () => {
51
+ const result = validateConfig({
52
+ config: {
53
+ scalars: "not an array",
54
+ },
55
+ configPath,
56
+ });
57
+ expect(result.valid).toBe(false);
58
+ expect(result.diagnostics.length).toBe(1);
59
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_TYPE");
60
+ expect(result.diagnostics[0]?.message).toContain("scalars");
61
+ });
62
+ it("should return error when scalar mapping is missing graphqlName", () => {
63
+ const result = validateConfig({
64
+ config: {
65
+ scalars: [
66
+ {
67
+ type: { from: "./src/scalars", name: "DateTime" },
68
+ },
69
+ ],
70
+ },
71
+ configPath,
72
+ });
73
+ expect(result.valid).toBe(false);
74
+ expect(result.diagnostics.length).toBe(1);
75
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_MISSING_PROPERTY");
76
+ expect(result.diagnostics[0]?.message).toContain("graphqlName");
77
+ });
78
+ it("should return error when scalar mapping is missing type", () => {
79
+ const result = validateConfig({
80
+ config: {
81
+ scalars: [
82
+ {
83
+ graphqlName: "DateTime",
84
+ },
85
+ ],
86
+ },
87
+ configPath,
88
+ });
89
+ expect(result.valid).toBe(false);
90
+ expect(result.diagnostics.length).toBe(1);
91
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_MISSING_PROPERTY");
92
+ expect(result.diagnostics[0]?.message).toContain("type");
93
+ });
94
+ it("should return error when type.from is missing", () => {
95
+ const result = validateConfig({
96
+ config: {
97
+ scalars: [
98
+ {
99
+ graphqlName: "DateTime",
100
+ type: { name: "DateTime" },
101
+ },
102
+ ],
103
+ },
104
+ configPath,
105
+ });
106
+ expect(result.valid).toBe(false);
107
+ expect(result.diagnostics.length).toBe(1);
108
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_MISSING_PROPERTY");
109
+ expect(result.diagnostics[0]?.message).toContain("type.from");
110
+ });
111
+ it("should return error when type.name is missing", () => {
112
+ const result = validateConfig({
113
+ config: {
114
+ scalars: [
115
+ {
116
+ graphqlName: "DateTime",
117
+ type: { from: "./src/scalars" },
118
+ },
119
+ ],
120
+ },
121
+ configPath,
122
+ });
123
+ expect(result.valid).toBe(false);
124
+ expect(result.diagnostics.length).toBe(1);
125
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_MISSING_PROPERTY");
126
+ expect(result.diagnostics[0]?.message).toContain("type.name");
127
+ });
128
+ describe("built-in scalar override", () => {
129
+ for (const builtinName of ["ID", "String", "Int", "Float", "Boolean"]) {
130
+ it(`should return error when overriding built-in scalar ${builtinName}`, () => {
131
+ const result = validateConfig({
132
+ config: {
133
+ scalars: [
134
+ {
135
+ graphqlName: builtinName,
136
+ type: { from: "./src/scalars", name: "Custom" },
137
+ },
138
+ ],
139
+ },
140
+ configPath,
141
+ });
142
+ expect(result.valid).toBe(false);
143
+ expect(result.diagnostics.length).toBe(1);
144
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_BUILTIN_OVERRIDE");
145
+ expect(result.diagnostics[0]?.message).toContain(builtinName);
146
+ });
147
+ }
148
+ });
149
+ describe("duplicate detection", () => {
150
+ it("should return error for duplicate graphqlName", () => {
151
+ const result = validateConfig({
152
+ config: {
153
+ scalars: [
154
+ {
155
+ graphqlName: "DateTime",
156
+ type: { from: "./src/scalars", name: "DateTime" },
157
+ },
158
+ {
159
+ graphqlName: "DateTime",
160
+ type: { from: "./src/other", name: "OtherDateTime" },
161
+ },
162
+ ],
163
+ },
164
+ configPath,
165
+ });
166
+ expect(result.valid).toBe(false);
167
+ expect(result.diagnostics.length).toBe(1);
168
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_DUPLICATE_MAPPING");
169
+ expect(result.diagnostics[0]?.message).toContain("DateTime");
170
+ });
171
+ it("should return error for duplicate type mapping", () => {
172
+ const result = validateConfig({
173
+ config: {
174
+ scalars: [
175
+ {
176
+ graphqlName: "DateTime",
177
+ type: { from: "./src/scalars", name: "DateTime" },
178
+ },
179
+ {
180
+ graphqlName: "Timestamp",
181
+ type: { from: "./src/scalars", name: "DateTime" },
182
+ },
183
+ ],
184
+ },
185
+ configPath,
186
+ });
187
+ expect(result.valid).toBe(false);
188
+ expect(result.diagnostics.length).toBe(1);
189
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_DUPLICATE_TYPE");
190
+ expect(result.diagnostics[0]?.message).toContain("DateTime");
191
+ });
192
+ it("should allow same type name from different paths", () => {
193
+ const result = validateConfig({
194
+ config: {
195
+ scalars: [
196
+ {
197
+ graphqlName: "DateTime",
198
+ type: { from: "./src/scalars", name: "DateTime" },
199
+ },
200
+ {
201
+ graphqlName: "CustomDateTime",
202
+ type: { from: "./src/custom", name: "DateTime" },
203
+ },
204
+ ],
205
+ },
206
+ configPath,
207
+ });
208
+ expect(result.valid).toBe(true);
209
+ expect(result.diagnostics.length).toBe(0);
210
+ });
211
+ });
212
+ describe("new scalar config format (name, tsType)", () => {
213
+ it("should accept new format with name and tsType.name", () => {
214
+ const result = validateConfig({
215
+ config: {
216
+ scalars: [
217
+ {
218
+ name: "DateTime",
219
+ tsType: { name: "Date" },
220
+ },
221
+ ],
222
+ },
223
+ configPath,
224
+ });
225
+ expect(result.valid).toBe(true);
226
+ expect(result.resolvedConfig).toBeTruthy();
227
+ expect(result.resolvedConfig.scalars.length).toBe(1);
228
+ expect(result.resolvedConfig.scalars[0]?.graphqlName).toBe("DateTime");
229
+ expect(result.resolvedConfig.scalars[0]?.typeName).toBe("Date");
230
+ expect(result.resolvedConfig.scalars[0]?.importPath).toBe(null);
231
+ });
232
+ it("should accept new format with tsType.from for module specification", () => {
233
+ const result = validateConfig({
234
+ config: {
235
+ scalars: [
236
+ {
237
+ name: "DateTime",
238
+ tsType: { name: "DateTimeString", from: "./src/types" },
239
+ },
240
+ ],
241
+ },
242
+ configPath,
243
+ });
244
+ expect(result.valid).toBe(true);
245
+ expect(result.resolvedConfig).toBeTruthy();
246
+ expect(result.resolvedConfig.scalars.length).toBe(1);
247
+ expect(result.resolvedConfig.scalars[0]?.graphqlName).toBe("DateTime");
248
+ expect(result.resolvedConfig.scalars[0]?.typeName).toBe("DateTimeString");
249
+ expect(result.resolvedConfig.scalars[0]?.importPath).toBe("./src/types");
250
+ });
251
+ it("should accept only option for input-only scalar", () => {
252
+ const result = validateConfig({
253
+ config: {
254
+ scalars: [
255
+ {
256
+ name: "DateTime",
257
+ tsType: { name: "Date" },
258
+ only: "input",
259
+ },
260
+ ],
261
+ },
262
+ configPath,
263
+ });
264
+ expect(result.valid).toBe(true);
265
+ expect(result.resolvedConfig).toBeTruthy();
266
+ expect(result.resolvedConfig.scalars[0]?.only).toBe("input");
267
+ });
268
+ it("should accept only option for output-only scalar", () => {
269
+ const result = validateConfig({
270
+ config: {
271
+ scalars: [
272
+ {
273
+ name: "DateTime",
274
+ tsType: { name: "Date" },
275
+ only: "output",
276
+ },
277
+ ],
278
+ },
279
+ configPath,
280
+ });
281
+ expect(result.valid).toBe(true);
282
+ expect(result.resolvedConfig).toBeTruthy();
283
+ expect(result.resolvedConfig.scalars[0]?.only).toBe("output");
284
+ });
285
+ it("should default only to null when not specified", () => {
286
+ const result = validateConfig({
287
+ config: {
288
+ scalars: [
289
+ {
290
+ name: "DateTime",
291
+ tsType: { name: "Date" },
292
+ },
293
+ ],
294
+ },
295
+ configPath,
296
+ });
297
+ expect(result.valid).toBe(true);
298
+ expect(result.resolvedConfig).toBeTruthy();
299
+ expect(result.resolvedConfig.scalars[0]?.only).toBe(null);
300
+ });
301
+ it("should accept description option", () => {
302
+ const result = validateConfig({
303
+ config: {
304
+ scalars: [
305
+ {
306
+ name: "DateTime",
307
+ tsType: { name: "Date" },
308
+ description: "ISO 8601 date-time format",
309
+ },
310
+ ],
311
+ },
312
+ configPath,
313
+ });
314
+ expect(result.valid).toBe(true);
315
+ expect(result.resolvedConfig).toBeTruthy();
316
+ expect(result.resolvedConfig.scalars[0]?.description).toBe("ISO 8601 date-time format");
317
+ });
318
+ it("should default description to null when not specified", () => {
319
+ const result = validateConfig({
320
+ config: {
321
+ scalars: [
322
+ {
323
+ name: "DateTime",
324
+ tsType: { name: "Date" },
325
+ },
326
+ ],
327
+ },
328
+ configPath,
329
+ });
330
+ expect(result.valid).toBe(true);
331
+ expect(result.resolvedConfig).toBeTruthy();
332
+ expect(result.resolvedConfig.scalars[0]?.description).toBe(null);
333
+ });
334
+ it("should return error for invalid only value", () => {
335
+ const result = validateConfig({
336
+ config: {
337
+ scalars: [
338
+ {
339
+ name: "DateTime",
340
+ tsType: { name: "Date" },
341
+ only: "invalid",
342
+ },
343
+ ],
344
+ },
345
+ configPath,
346
+ });
347
+ expect(result.valid).toBe(false);
348
+ expect(result.diagnostics.length).toBe(1);
349
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_ONLY_VALUE");
350
+ expect(result.diagnostics[0]?.message).toContain("only");
351
+ });
352
+ it("should return error when name is missing in new format", () => {
353
+ const result = validateConfig({
354
+ config: {
355
+ scalars: [
356
+ {
357
+ tsType: { name: "Date" },
358
+ },
359
+ ],
360
+ },
361
+ configPath,
362
+ });
363
+ expect(result.valid).toBe(false);
364
+ expect(result.diagnostics.length).toBe(1);
365
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_MISSING_PROPERTY");
366
+ });
367
+ it("should return error when tsType.name is missing", () => {
368
+ const result = validateConfig({
369
+ config: {
370
+ scalars: [
371
+ {
372
+ name: "DateTime",
373
+ tsType: {},
374
+ },
375
+ ],
376
+ },
377
+ configPath,
378
+ });
379
+ expect(result.valid).toBe(false);
380
+ expect(result.diagnostics.length).toBe(1);
381
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_MISSING_PROPERTY");
382
+ expect(result.diagnostics[0]?.message).toContain("tsType.name");
383
+ });
384
+ it("should allow multiple mappings for same scalar name with different only values", () => {
385
+ const result = validateConfig({
386
+ config: {
387
+ scalars: [
388
+ {
389
+ name: "DateTime",
390
+ tsType: { name: "Date" },
391
+ only: "input",
392
+ },
393
+ {
394
+ name: "DateTime",
395
+ tsType: { name: "DateTimeOutput", from: "./src/types" },
396
+ only: "output",
397
+ },
398
+ ],
399
+ },
400
+ configPath,
401
+ });
402
+ expect(result.valid).toBe(true);
403
+ expect(result.resolvedConfig).toBeTruthy();
404
+ expect(result.resolvedConfig.scalars.length).toBe(2);
405
+ expect(result.resolvedConfig.scalars[0]?.graphqlName).toBe("DateTime");
406
+ expect(result.resolvedConfig.scalars[0]?.only).toBe("input");
407
+ expect(result.resolvedConfig.scalars[1]?.graphqlName).toBe("DateTime");
408
+ expect(result.resolvedConfig.scalars[1]?.only).toBe("output");
409
+ });
410
+ it("should return error for built-in scalar override in new format", () => {
411
+ const result = validateConfig({
412
+ config: {
413
+ scalars: [
414
+ {
415
+ name: "String",
416
+ tsType: { name: "CustomString" },
417
+ },
418
+ ],
419
+ },
420
+ configPath,
421
+ });
422
+ expect(result.valid).toBe(false);
423
+ expect(result.diagnostics.length).toBe(1);
424
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_BUILTIN_OVERRIDE");
425
+ });
426
+ });
427
+ describe("output options (legacy tests - updated to new format)", () => {
428
+ it("should return error for invalid output type (not object)", () => {
429
+ const result = validateConfig({
430
+ config: {
431
+ output: "invalid",
432
+ },
433
+ configPath,
434
+ });
435
+ expect(result.valid).toBe(false);
436
+ expect(result.diagnostics.length).toBe(1);
437
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_TYPE");
438
+ expect(result.diagnostics[0]?.message).toContain("output");
439
+ });
440
+ });
441
+ describe("tsconfigPath options", () => {
442
+ it("should resolve tsconfigPath to null when not provided", () => {
443
+ const result = validateConfig({
444
+ config: {},
445
+ configPath,
446
+ });
447
+ expect(result.valid).toBe(true);
448
+ expect(result.resolvedConfig).toBeTruthy();
449
+ expect(result.resolvedConfig.tsconfigPath).toBe(null);
450
+ });
451
+ it("should accept string tsconfigPath", () => {
452
+ const result = validateConfig({
453
+ config: {
454
+ tsconfigPath: "./tsconfig.build.json",
455
+ },
456
+ configPath,
457
+ });
458
+ expect(result.valid).toBe(true);
459
+ expect(result.resolvedConfig).toBeTruthy();
460
+ expect(result.resolvedConfig.tsconfigPath).toBe("./tsconfig.build.json");
461
+ });
462
+ it("should return error for invalid tsconfigPath type", () => {
463
+ const result = validateConfig({
464
+ config: {
465
+ tsconfigPath: 123,
466
+ },
467
+ configPath,
468
+ });
469
+ expect(result.valid).toBe(false);
470
+ expect(result.diagnostics.length).toBe(1);
471
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_TYPE");
472
+ expect(result.diagnostics[0]?.message).toContain("tsconfigPath");
473
+ });
474
+ it("should return error for empty tsconfigPath", () => {
475
+ const result = validateConfig({
476
+ config: {
477
+ tsconfigPath: "",
478
+ },
479
+ configPath,
480
+ });
481
+ expect(result.valid).toBe(false);
482
+ expect(result.diagnostics.length).toBe(1);
483
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_PATH");
484
+ expect(result.diagnostics[0]?.message).toContain("empty");
485
+ });
486
+ });
487
+ describe("sourceDir options", () => {
488
+ it("should resolve default sourceDir when not provided", () => {
489
+ const result = validateConfig({
490
+ config: {},
491
+ configPath,
492
+ });
493
+ expect(result.valid).toBe(true);
494
+ expect(result.resolvedConfig).toBeTruthy();
495
+ expect(result.resolvedConfig.sourceDir).toBe("src/gqlkit/schema");
496
+ });
497
+ it("should accept valid sourceDir string", () => {
498
+ const result = validateConfig({
499
+ config: {
500
+ sourceDir: "src/graphql",
501
+ },
502
+ configPath,
503
+ });
504
+ expect(result.valid).toBe(true);
505
+ expect(result.resolvedConfig).toBeTruthy();
506
+ expect(result.resolvedConfig.sourceDir).toBe("src/graphql");
507
+ });
508
+ it("should return error for empty sourceDir", () => {
509
+ const result = validateConfig({
510
+ config: {
511
+ sourceDir: "",
512
+ },
513
+ configPath,
514
+ });
515
+ expect(result.valid).toBe(false);
516
+ expect(result.diagnostics.length).toBe(1);
517
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_SOURCE_DIR");
518
+ expect(result.diagnostics[0]?.message).toContain("cannot be empty");
519
+ });
520
+ it("should return error for non-string sourceDir", () => {
521
+ const result = validateConfig({
522
+ config: {
523
+ sourceDir: 123,
524
+ },
525
+ configPath,
526
+ });
527
+ expect(result.valid).toBe(false);
528
+ expect(result.diagnostics.length).toBe(1);
529
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_TYPE");
530
+ expect(result.diagnostics[0]?.message).toContain("sourceDir");
531
+ });
532
+ });
533
+ describe("sourceIgnoreGlobs options", () => {
534
+ it("should resolve default sourceIgnoreGlobs when not provided", () => {
535
+ const result = validateConfig({
536
+ config: {},
537
+ configPath,
538
+ });
539
+ expect(result.valid).toBe(true);
540
+ expect(result.resolvedConfig).toBeTruthy();
541
+ expect(result.resolvedConfig.sourceIgnoreGlobs).toEqual([]);
542
+ });
543
+ it("should accept valid glob patterns array", () => {
544
+ const result = validateConfig({
545
+ config: {
546
+ sourceIgnoreGlobs: ["**/*.test.ts", "**/__tests__/**"],
547
+ },
548
+ configPath,
549
+ });
550
+ expect(result.valid).toBe(true);
551
+ expect(result.resolvedConfig).toBeTruthy();
552
+ expect(result.resolvedConfig.sourceIgnoreGlobs).toEqual([
553
+ "**/*.test.ts",
554
+ "**/__tests__/**",
555
+ ]);
556
+ });
557
+ it("should accept empty array", () => {
558
+ const result = validateConfig({
559
+ config: {
560
+ sourceIgnoreGlobs: [],
561
+ },
562
+ configPath,
563
+ });
564
+ expect(result.valid).toBe(true);
565
+ expect(result.resolvedConfig).toBeTruthy();
566
+ expect(result.resolvedConfig.sourceIgnoreGlobs).toEqual([]);
567
+ });
568
+ it("should return error for non-array sourceIgnoreGlobs", () => {
569
+ const result = validateConfig({
570
+ config: {
571
+ sourceIgnoreGlobs: "**/*.test.ts",
572
+ },
573
+ configPath,
574
+ });
575
+ expect(result.valid).toBe(false);
576
+ expect(result.diagnostics.length).toBe(1);
577
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_IGNORE_GLOBS");
578
+ expect(result.diagnostics[0]?.message).toContain("must be an array of strings");
579
+ });
580
+ it("should return error for array with non-string elements", () => {
581
+ const result = validateConfig({
582
+ config: {
583
+ sourceIgnoreGlobs: ["valid", 123, "also-valid"],
584
+ },
585
+ configPath,
586
+ });
587
+ expect(result.valid).toBe(false);
588
+ expect(result.diagnostics.length).toBe(1);
589
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_IGNORE_GLOBS");
590
+ expect(result.diagnostics[0]?.message).toContain("must be an array of strings");
591
+ });
592
+ });
593
+ describe("new output options (resolversPath, typeDefsPath, schemaPath)", () => {
594
+ it("should resolve default output paths when output is undefined", () => {
595
+ const result = validateConfig({
596
+ config: {},
597
+ configPath,
598
+ });
599
+ expect(result.valid).toBe(true);
600
+ expect(result.resolvedConfig).toBeTruthy();
601
+ expect(result.resolvedConfig.output.resolversPath).toBe("src/gqlkit/__generated__/resolvers.ts");
602
+ expect(result.resolvedConfig.output.typeDefsPath).toBe("src/gqlkit/__generated__/typeDefs.ts");
603
+ expect(result.resolvedConfig.output.schemaPath).toBe("src/gqlkit/__generated__/schema.graphql");
604
+ });
605
+ it("should resolve default paths when individual options are undefined", () => {
606
+ const result = validateConfig({
607
+ config: { output: {} },
608
+ configPath,
609
+ });
610
+ expect(result.valid).toBe(true);
611
+ expect(result.resolvedConfig).toBeTruthy();
612
+ expect(result.resolvedConfig.output.resolversPath).toBe("src/gqlkit/__generated__/resolvers.ts");
613
+ expect(result.resolvedConfig.output.typeDefsPath).toBe("src/gqlkit/__generated__/typeDefs.ts");
614
+ expect(result.resolvedConfig.output.schemaPath).toBe("src/gqlkit/__generated__/schema.graphql");
615
+ });
616
+ it("should use custom paths when provided", () => {
617
+ const result = validateConfig({
618
+ config: {
619
+ output: {
620
+ resolversPath: "custom/resolvers.ts",
621
+ typeDefsPath: "custom/typeDefs.ts",
622
+ schemaPath: "custom/schema.graphql",
623
+ },
624
+ },
625
+ configPath,
626
+ });
627
+ expect(result.valid).toBe(true);
628
+ expect(result.resolvedConfig).toBeTruthy();
629
+ expect(result.resolvedConfig.output.resolversPath).toBe("custom/resolvers.ts");
630
+ expect(result.resolvedConfig.output.typeDefsPath).toBe("custom/typeDefs.ts");
631
+ expect(result.resolvedConfig.output.schemaPath).toBe("custom/schema.graphql");
632
+ });
633
+ it("should allow null to suppress output for each path", () => {
634
+ const result = validateConfig({
635
+ config: {
636
+ output: {
637
+ resolversPath: null,
638
+ typeDefsPath: null,
639
+ schemaPath: null,
640
+ },
641
+ },
642
+ configPath,
643
+ });
644
+ expect(result.valid).toBe(true);
645
+ expect(result.resolvedConfig).toBeTruthy();
646
+ expect(result.resolvedConfig.output.resolversPath).toBe(null);
647
+ expect(result.resolvedConfig.output.typeDefsPath).toBe(null);
648
+ expect(result.resolvedConfig.output.schemaPath).toBe(null);
649
+ });
650
+ it("should allow mixed null and string", () => {
651
+ const result = validateConfig({
652
+ config: {
653
+ output: {
654
+ resolversPath: "custom/resolvers.ts",
655
+ typeDefsPath: null,
656
+ schemaPath: "custom/schema.graphql",
657
+ },
658
+ },
659
+ configPath,
660
+ });
661
+ expect(result.valid).toBe(true);
662
+ expect(result.resolvedConfig).toBeTruthy();
663
+ expect(result.resolvedConfig.output.resolversPath).toBe("custom/resolvers.ts");
664
+ expect(result.resolvedConfig.output.typeDefsPath).toBe(null);
665
+ expect(result.resolvedConfig.output.schemaPath).toBe("custom/schema.graphql");
666
+ });
667
+ it("should return error for invalid resolversPath type", () => {
668
+ const result = validateConfig({
669
+ config: {
670
+ output: {
671
+ resolversPath: 123,
672
+ },
673
+ },
674
+ configPath,
675
+ });
676
+ expect(result.valid).toBe(false);
677
+ expect(result.diagnostics.length).toBe(1);
678
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_OUTPUT_TYPE");
679
+ expect(result.diagnostics[0]?.message).toContain("output.resolversPath");
680
+ });
681
+ it("should return error for invalid typeDefsPath type", () => {
682
+ const result = validateConfig({
683
+ config: {
684
+ output: {
685
+ typeDefsPath: true,
686
+ },
687
+ },
688
+ configPath,
689
+ });
690
+ expect(result.valid).toBe(false);
691
+ expect(result.diagnostics.length).toBe(1);
692
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_OUTPUT_TYPE");
693
+ expect(result.diagnostics[0]?.message).toContain("output.typeDefsPath");
694
+ });
695
+ it("should return error for empty string resolversPath", () => {
696
+ const result = validateConfig({
697
+ config: {
698
+ output: {
699
+ resolversPath: "",
700
+ },
701
+ },
702
+ configPath,
703
+ });
704
+ expect(result.valid).toBe(false);
705
+ expect(result.diagnostics.length).toBe(1);
706
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_OUTPUT_PATH");
707
+ expect(result.diagnostics[0]?.message).toContain("empty");
708
+ });
709
+ });
710
+ describe("hooks options", () => {
711
+ it("should resolve default empty hooks when not provided", () => {
712
+ const result = validateConfig({
713
+ config: {},
714
+ configPath,
715
+ });
716
+ expect(result.valid).toBe(true);
717
+ expect(result.resolvedConfig).toBeTruthy();
718
+ expect(result.resolvedConfig.hooks.afterAllFileWrite).toEqual([]);
719
+ });
720
+ it("should accept single command string for afterAllFileWrite", () => {
721
+ const result = validateConfig({
722
+ config: {
723
+ hooks: {
724
+ afterAllFileWrite: "prettier --write",
725
+ },
726
+ },
727
+ configPath,
728
+ });
729
+ expect(result.valid).toBe(true);
730
+ expect(result.resolvedConfig).toBeTruthy();
731
+ expect(result.resolvedConfig.hooks.afterAllFileWrite).toEqual([
732
+ "prettier --write",
733
+ ]);
734
+ });
735
+ it("should accept array of command strings for afterAllFileWrite", () => {
736
+ const result = validateConfig({
737
+ config: {
738
+ hooks: {
739
+ afterAllFileWrite: ["prettier --write", "eslint --fix"],
740
+ },
741
+ },
742
+ configPath,
743
+ });
744
+ expect(result.valid).toBe(true);
745
+ expect(result.resolvedConfig).toBeTruthy();
746
+ expect(result.resolvedConfig.hooks.afterAllFileWrite).toEqual([
747
+ "prettier --write",
748
+ "eslint --fix",
749
+ ]);
750
+ });
751
+ it("should accept empty array for afterAllFileWrite", () => {
752
+ const result = validateConfig({
753
+ config: {
754
+ hooks: {
755
+ afterAllFileWrite: [],
756
+ },
757
+ },
758
+ configPath,
759
+ });
760
+ expect(result.valid).toBe(true);
761
+ expect(result.resolvedConfig).toBeTruthy();
762
+ expect(result.resolvedConfig.hooks.afterAllFileWrite).toEqual([]);
763
+ });
764
+ it("should accept hooks object without afterAllFileWrite", () => {
765
+ const result = validateConfig({
766
+ config: {
767
+ hooks: {},
768
+ },
769
+ configPath,
770
+ });
771
+ expect(result.valid).toBe(true);
772
+ expect(result.resolvedConfig).toBeTruthy();
773
+ expect(result.resolvedConfig.hooks.afterAllFileWrite).toEqual([]);
774
+ });
775
+ it("should return error for non-object hooks", () => {
776
+ const result = validateConfig({
777
+ config: {
778
+ hooks: "invalid",
779
+ },
780
+ configPath,
781
+ });
782
+ expect(result.valid).toBe(false);
783
+ expect(result.diagnostics.length).toBe(1);
784
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_TYPE");
785
+ expect(result.diagnostics[0]?.message).toContain("hooks");
786
+ });
787
+ it("should return error for invalid afterAllFileWrite type", () => {
788
+ const result = validateConfig({
789
+ config: {
790
+ hooks: {
791
+ afterAllFileWrite: 123,
792
+ },
793
+ },
794
+ configPath,
795
+ });
796
+ expect(result.valid).toBe(false);
797
+ expect(result.diagnostics.length).toBe(1);
798
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_HOOK_TYPE");
799
+ expect(result.diagnostics[0]?.message).toContain("afterAllFileWrite");
800
+ });
801
+ it("should return error for array with non-string elements", () => {
802
+ const result = validateConfig({
803
+ config: {
804
+ hooks: {
805
+ afterAllFileWrite: ["valid", 123, "also-valid"],
806
+ },
807
+ },
808
+ configPath,
809
+ });
810
+ expect(result.valid).toBe(false);
811
+ expect(result.diagnostics.length).toBe(1);
812
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_HOOK_TYPE");
813
+ expect(result.diagnostics[0]?.message).toContain("afterAllFileWrite");
814
+ });
815
+ it("should return error for empty command string", () => {
816
+ const result = validateConfig({
817
+ config: {
818
+ hooks: {
819
+ afterAllFileWrite: "",
820
+ },
821
+ },
822
+ configPath,
823
+ });
824
+ expect(result.valid).toBe(false);
825
+ expect(result.diagnostics.length).toBe(1);
826
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_HOOK_COMMAND");
827
+ expect(result.diagnostics[0]?.message).toContain("empty");
828
+ });
829
+ it("should return error for array containing empty string", () => {
830
+ const result = validateConfig({
831
+ config: {
832
+ hooks: {
833
+ afterAllFileWrite: ["prettier --write", "", "eslint --fix"],
834
+ },
835
+ },
836
+ configPath,
837
+ });
838
+ expect(result.valid).toBe(false);
839
+ expect(result.diagnostics.length).toBe(1);
840
+ expect(result.diagnostics[0]?.code).toBe("CONFIG_INVALID_HOOK_COMMAND");
841
+ expect(result.diagnostics[0]?.message).toContain("empty");
842
+ });
843
+ });
844
+ });
845
+ });
846
+ //# sourceMappingURL=validator.test.js.map