@unispechq/unispec-core 0.3.0 → 0.3.2

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 (306) hide show
  1. package/dist/cjs/diff/annotators.js +36 -9
  2. package/dist/cjs/src/cache/cache-factory.js +72 -0
  3. package/dist/cjs/src/cache/cache-manager.js +128 -0
  4. package/dist/cjs/src/cache/constants.js +25 -0
  5. package/dist/cjs/src/cache/hash-utils.js +19 -0
  6. package/dist/cjs/src/cache/hashing.js +230 -0
  7. package/dist/cjs/src/cache/index.js +24 -0
  8. package/dist/cjs/src/cache/lru-cache.js +144 -0
  9. package/dist/cjs/src/cache/types.js +5 -0
  10. package/dist/cjs/src/diff/annotators.js +160 -0
  11. package/dist/cjs/src/diff/change-reports.js +369 -0
  12. package/dist/cjs/src/diff/core.js +158 -0
  13. package/dist/cjs/src/diff/enhanced-diff.js +65 -0
  14. package/dist/cjs/src/diff/impact-strategies-refactored.js +230 -0
  15. package/dist/cjs/src/diff/impact-strategies.js +219 -0
  16. package/dist/cjs/src/diff/index.js +27 -0
  17. package/dist/cjs/src/diff/metrics-calculator.js +69 -0
  18. package/dist/cjs/src/diff/risk-calculator.js +58 -0
  19. package/dist/cjs/src/diff/suggestion-generator.js +78 -0
  20. package/dist/cjs/src/diff/types.js +11 -0
  21. package/dist/cjs/src/errors/base-error.js +33 -0
  22. package/dist/cjs/src/errors/config-error.js +11 -0
  23. package/dist/cjs/src/errors/error-factory.js +48 -0
  24. package/dist/cjs/src/errors/index.js +19 -0
  25. package/dist/cjs/src/errors/loader-error.js +11 -0
  26. package/dist/cjs/src/errors/reference-error.js +11 -0
  27. package/dist/cjs/src/errors/schema-error.js +11 -0
  28. package/dist/cjs/src/errors/security-error.js +11 -0
  29. package/dist/cjs/src/errors/semantic-error.js +11 -0
  30. package/dist/cjs/src/generated-schemas.js +2100 -0
  31. package/dist/cjs/src/index.js +59 -0
  32. package/dist/cjs/src/loader/index.js +13 -0
  33. package/dist/cjs/src/loader/security-validator.js +53 -0
  34. package/dist/cjs/src/loader/types.js +11 -0
  35. package/dist/cjs/src/loader/unispec-loader.js +84 -0
  36. package/dist/cjs/src/loader/yaml-loader.js +76 -0
  37. package/dist/cjs/src/normalizer/core.js +37 -0
  38. package/dist/cjs/src/normalizer/graphql-normalizer.js +67 -0
  39. package/dist/cjs/src/normalizer/index.js +7 -0
  40. package/dist/cjs/src/normalizer/rest-normalizer.js +51 -0
  41. package/dist/cjs/src/normalizer/types.js +2 -0
  42. package/dist/cjs/src/normalizer/utils.js +49 -0
  43. package/dist/cjs/src/normalizer/websocket-normalizer.js +81 -0
  44. package/dist/cjs/src/optimizer/core.js +140 -0
  45. package/dist/cjs/src/optimizer/index.js +17 -0
  46. package/dist/cjs/src/optimizer/optimization-functions.js +185 -0
  47. package/dist/cjs/src/optimizer/types.js +2 -0
  48. package/dist/cjs/src/optimizer/utils.js +32 -0
  49. package/dist/cjs/src/schemas/dedupe.js +113 -0
  50. package/dist/cjs/src/schemas/index.js +14 -0
  51. package/dist/cjs/src/schemas/resolver.js +42 -0
  52. package/dist/cjs/src/schemas/utils.js +53 -0
  53. package/dist/cjs/src/types/index.js +2 -0
  54. package/dist/cjs/src/validator/ajv-validator.js +82 -0
  55. package/dist/cjs/src/validator/config-validator-main.js +34 -0
  56. package/dist/cjs/src/validator/config-validator.js +17 -0
  57. package/dist/cjs/src/validator/index.js +23 -0
  58. package/dist/cjs/src/validator/object-traversal.js +112 -0
  59. package/dist/cjs/src/validator/reference-validator.js +233 -0
  60. package/dist/cjs/src/validator/schema-references.js +116 -0
  61. package/dist/cjs/src/validator/semantic-validator.js +328 -0
  62. package/dist/cjs/src/validator/tests-validator.js +16 -0
  63. package/dist/cjs/src/validator/types.js +2 -0
  64. package/dist/cjs/src/validator/unispec-validator.js +80 -0
  65. package/dist/cjs/src/validator/validator-factory.js +77 -0
  66. package/dist/cjs/src/versions.js +147 -0
  67. package/dist/cjs/tests/cache/cache.test.js +274 -0
  68. package/dist/cjs/tests/cache/utils.js +32 -0
  69. package/dist/cjs/tests/concurrency-normalizer-optimizer.test.js +1 -0
  70. package/dist/cjs/tests/diff/diff-annotators.test.js +280 -0
  71. package/dist/cjs/tests/diff/diff-comprehensive.test.js +262 -0
  72. package/dist/cjs/tests/diff/diff-extended.test.js +235 -0
  73. package/dist/cjs/tests/diff/diff.test.js +189 -0
  74. package/dist/cjs/tests/diff/utils.js +8 -0
  75. package/dist/cjs/tests/errors/errors-integration.test.js +173 -0
  76. package/dist/cjs/tests/errors/errors.test.js +280 -0
  77. package/dist/cjs/tests/errors/utils.js +7 -0
  78. package/dist/cjs/tests/loader/integration.test.js +216 -0
  79. package/dist/cjs/tests/loader/loader.test.js +341 -0
  80. package/dist/cjs/tests/normalizer/normalizer-comprehensive.test.js +648 -0
  81. package/dist/cjs/tests/normalizer/normalizer-invalid.test.js +258 -0
  82. package/dist/cjs/tests/normalizer/normalizer-valid.test.js +238 -0
  83. package/dist/cjs/tests/normalizer/utils.js +47 -0
  84. package/dist/cjs/tests/optimizer/compress-references.test.js +304 -0
  85. package/dist/cjs/tests/optimizer/deduplication.test.js +132 -0
  86. package/dist/cjs/tests/optimizer/integration.test.js +131 -0
  87. package/dist/cjs/tests/optimizer/optimization-report.test.js +222 -0
  88. package/dist/cjs/tests/optimizer/optimize-document.test.js +187 -0
  89. package/dist/cjs/tests/optimizer/orphaned-schemas.test.js +194 -0
  90. package/dist/cjs/tests/optimizer/sort-schemas.test.js +131 -0
  91. package/dist/cjs/tests/optimizer/utils.js +209 -0
  92. package/dist/cjs/tests/schemas/schemas-edge-cases.test.js +223 -0
  93. package/dist/cjs/tests/schemas/schemas.test.js +400 -0
  94. package/dist/cjs/tests/schemas/utils.js +7 -0
  95. package/dist/cjs/tests/utils.js +131 -0
  96. package/dist/cjs/tests/validator/config-validator.test.js +78 -0
  97. package/dist/cjs/tests/validator/debug-config.js +1 -0
  98. package/dist/cjs/tests/validator/debug-missing-service.js +1 -0
  99. package/dist/cjs/tests/validator/debug-other-configs.js +1 -0
  100. package/dist/cjs/tests/validator/debug-references.js +1 -0
  101. package/dist/cjs/tests/validator/unispec-validator.test.js +103 -0
  102. package/dist/cjs/tests/validator/utils.js +25 -0
  103. package/dist/diff/annotators.js +36 -9
  104. package/dist/src/cache/cache-factory.d.ts +31 -0
  105. package/dist/src/cache/cache-factory.js +65 -0
  106. package/dist/src/cache/cache-manager.d.ts +62 -0
  107. package/dist/src/cache/cache-manager.js +124 -0
  108. package/dist/src/cache/constants.d.ts +21 -0
  109. package/dist/src/cache/constants.js +22 -0
  110. package/dist/src/cache/hash-utils.d.ts +11 -0
  111. package/dist/src/cache/hash-utils.js +15 -0
  112. package/dist/src/cache/hashing.d.ts +28 -0
  113. package/dist/src/cache/hashing.js +193 -0
  114. package/dist/src/cache/index.d.ts +6 -0
  115. package/dist/src/cache/index.js +10 -0
  116. package/dist/src/cache/lru-cache.d.ts +44 -0
  117. package/dist/src/cache/lru-cache.js +140 -0
  118. package/dist/src/cache/types.d.ts +24 -0
  119. package/dist/src/cache/types.js +4 -0
  120. package/dist/src/diff/annotators.d.ts +4 -0
  121. package/dist/src/diff/annotators.js +155 -0
  122. package/dist/src/diff/change-reports.d.ts +37 -0
  123. package/dist/src/diff/change-reports.js +366 -0
  124. package/dist/src/diff/core.d.ts +26 -0
  125. package/dist/src/diff/core.js +155 -0
  126. package/dist/src/diff/enhanced-diff.d.ts +51 -0
  127. package/dist/src/diff/enhanced-diff.js +62 -0
  128. package/dist/src/diff/impact-strategies-refactored.d.ts +69 -0
  129. package/dist/src/diff/impact-strategies-refactored.js +223 -0
  130. package/dist/src/diff/impact-strategies.d.ts +41 -0
  131. package/dist/src/diff/impact-strategies.js +212 -0
  132. package/dist/src/diff/index.d.ts +8 -0
  133. package/dist/src/diff/index.js +11 -0
  134. package/dist/src/diff/metrics-calculator.d.ts +23 -0
  135. package/dist/src/diff/metrics-calculator.js +65 -0
  136. package/dist/src/diff/risk-calculator.d.ts +23 -0
  137. package/dist/src/diff/risk-calculator.js +55 -0
  138. package/dist/src/diff/suggestion-generator.d.ts +18 -0
  139. package/dist/src/diff/suggestion-generator.js +74 -0
  140. package/dist/src/diff/types.d.ts +24 -0
  141. package/dist/src/diff/types.js +8 -0
  142. package/dist/src/errors/base-error.d.ts +20 -0
  143. package/dist/src/errors/base-error.js +29 -0
  144. package/dist/src/errors/config-error.d.ts +4 -0
  145. package/dist/src/errors/config-error.js +7 -0
  146. package/dist/src/errors/error-factory.d.ts +22 -0
  147. package/dist/src/errors/error-factory.js +45 -0
  148. package/dist/src/errors/index.d.ts +8 -0
  149. package/dist/src/errors/index.js +8 -0
  150. package/dist/src/errors/loader-error.d.ts +4 -0
  151. package/dist/src/errors/loader-error.js +7 -0
  152. package/dist/src/errors/reference-error.d.ts +4 -0
  153. package/dist/src/errors/reference-error.js +7 -0
  154. package/dist/src/errors/schema-error.d.ts +4 -0
  155. package/dist/src/errors/schema-error.js +7 -0
  156. package/dist/src/errors/security-error.d.ts +4 -0
  157. package/dist/src/errors/security-error.js +7 -0
  158. package/dist/src/errors/semantic-error.d.ts +4 -0
  159. package/dist/src/errors/semantic-error.js +7 -0
  160. package/dist/src/generated-schemas.d.ts +2073 -0
  161. package/dist/src/generated-schemas.js +2097 -0
  162. package/dist/src/index.d.ts +13 -0
  163. package/dist/src/index.js +43 -0
  164. package/dist/src/loader/index.d.ts +5 -0
  165. package/dist/src/loader/index.js +5 -0
  166. package/dist/src/loader/security-validator.d.ts +5 -0
  167. package/dist/src/loader/security-validator.js +50 -0
  168. package/dist/src/loader/types.d.ts +30 -0
  169. package/dist/src/loader/types.js +8 -0
  170. package/dist/src/loader/unispec-loader.d.ts +10 -0
  171. package/dist/src/loader/unispec-loader.js +81 -0
  172. package/dist/src/loader/yaml-loader.d.ts +10 -0
  173. package/dist/src/loader/yaml-loader.js +39 -0
  174. package/dist/src/normalizer/core.d.ts +24 -0
  175. package/dist/src/normalizer/core.js +34 -0
  176. package/dist/src/normalizer/graphql-normalizer.d.ts +8 -0
  177. package/dist/src/normalizer/graphql-normalizer.js +64 -0
  178. package/dist/src/normalizer/index.d.ts +2 -0
  179. package/dist/src/normalizer/index.js +3 -0
  180. package/dist/src/normalizer/rest-normalizer.d.ts +8 -0
  181. package/dist/src/normalizer/rest-normalizer.js +48 -0
  182. package/dist/src/normalizer/types.d.ts +7 -0
  183. package/dist/src/normalizer/types.js +1 -0
  184. package/dist/src/normalizer/utils.d.ts +17 -0
  185. package/dist/src/normalizer/utils.js +45 -0
  186. package/dist/src/normalizer/websocket-normalizer.d.ts +8 -0
  187. package/dist/src/normalizer/websocket-normalizer.js +78 -0
  188. package/dist/src/optimizer/core.d.ts +17 -0
  189. package/dist/src/optimizer/core.js +136 -0
  190. package/dist/src/optimizer/index.d.ts +4 -0
  191. package/dist/src/optimizer/index.js +7 -0
  192. package/dist/src/optimizer/optimization-functions.d.ts +32 -0
  193. package/dist/src/optimizer/optimization-functions.js +179 -0
  194. package/dist/src/optimizer/types.d.ts +28 -0
  195. package/dist/src/optimizer/types.js +1 -0
  196. package/dist/src/optimizer/utils.d.ts +7 -0
  197. package/dist/src/optimizer/utils.js +29 -0
  198. package/dist/src/schemas/dedupe.d.ts +9 -0
  199. package/dist/src/schemas/dedupe.js +110 -0
  200. package/dist/src/schemas/index.d.ts +3 -0
  201. package/dist/src/schemas/index.js +6 -0
  202. package/dist/src/schemas/resolver.d.ts +19 -0
  203. package/dist/src/schemas/resolver.js +38 -0
  204. package/dist/src/schemas/utils.d.ts +20 -0
  205. package/dist/src/schemas/utils.js +49 -0
  206. package/dist/src/types/index.d.ts +434 -0
  207. package/dist/src/types/index.js +1 -0
  208. package/dist/src/validator/ajv-validator.d.ts +15 -0
  209. package/dist/src/validator/ajv-validator.js +75 -0
  210. package/dist/src/validator/config-validator-main.d.ts +10 -0
  211. package/dist/src/validator/config-validator-main.js +31 -0
  212. package/dist/src/validator/config-validator.d.ts +5 -0
  213. package/dist/src/validator/config-validator.js +14 -0
  214. package/dist/src/validator/index.d.ts +10 -0
  215. package/dist/src/validator/index.js +11 -0
  216. package/dist/src/validator/object-traversal.d.ts +52 -0
  217. package/dist/src/validator/object-traversal.js +104 -0
  218. package/dist/src/validator/reference-validator.d.ts +31 -0
  219. package/dist/src/validator/reference-validator.js +230 -0
  220. package/dist/src/validator/schema-references.d.ts +23 -0
  221. package/dist/src/validator/schema-references.js +111 -0
  222. package/dist/src/validator/semantic-validator.d.ts +26 -0
  223. package/dist/src/validator/semantic-validator.js +325 -0
  224. package/dist/src/validator/tests-validator.d.ts +9 -0
  225. package/dist/src/validator/tests-validator.js +13 -0
  226. package/dist/src/validator/types.d.ts +29 -0
  227. package/dist/src/validator/types.js +1 -0
  228. package/dist/src/validator/unispec-validator.d.ts +15 -0
  229. package/dist/src/validator/unispec-validator.js +77 -0
  230. package/dist/src/validator/validator-factory.d.ts +10 -0
  231. package/dist/src/validator/validator-factory.js +73 -0
  232. package/dist/src/versions.d.ts +10 -0
  233. package/dist/src/versions.js +143 -0
  234. package/dist/tests/cache/cache.test.d.ts +1 -0
  235. package/dist/tests/cache/cache.test.js +269 -0
  236. package/dist/tests/cache/utils.d.ts +4 -0
  237. package/dist/tests/cache/utils.js +24 -0
  238. package/dist/tests/concurrency-normalizer-optimizer.test.d.ts +0 -0
  239. package/dist/tests/concurrency-normalizer-optimizer.test.js +1 -0
  240. package/dist/tests/diff/diff-annotators.test.d.ts +1 -0
  241. package/dist/tests/diff/diff-annotators.test.js +275 -0
  242. package/dist/tests/diff/diff-comprehensive.test.d.ts +1 -0
  243. package/dist/tests/diff/diff-comprehensive.test.js +257 -0
  244. package/dist/tests/diff/diff-extended.test.d.ts +1 -0
  245. package/dist/tests/diff/diff-extended.test.js +230 -0
  246. package/dist/tests/diff/diff.test.d.ts +1 -0
  247. package/dist/tests/diff/diff.test.js +184 -0
  248. package/dist/tests/diff/utils.d.ts +2 -0
  249. package/dist/tests/diff/utils.js +3 -0
  250. package/dist/tests/errors/errors-integration.test.d.ts +1 -0
  251. package/dist/tests/errors/errors-integration.test.js +168 -0
  252. package/dist/tests/errors/errors.test.d.ts +1 -0
  253. package/dist/tests/errors/errors.test.js +275 -0
  254. package/dist/tests/errors/utils.d.ts +2 -0
  255. package/dist/tests/errors/utils.js +3 -0
  256. package/dist/tests/loader/integration.test.d.ts +1 -0
  257. package/dist/tests/loader/integration.test.js +211 -0
  258. package/dist/tests/loader/loader.test.d.ts +1 -0
  259. package/dist/tests/loader/loader.test.js +336 -0
  260. package/dist/tests/normalizer/normalizer-comprehensive.test.d.ts +1 -0
  261. package/dist/tests/normalizer/normalizer-comprehensive.test.js +643 -0
  262. package/dist/tests/normalizer/normalizer-invalid.test.d.ts +1 -0
  263. package/dist/tests/normalizer/normalizer-invalid.test.js +253 -0
  264. package/dist/tests/normalizer/normalizer-valid.test.d.ts +1 -0
  265. package/dist/tests/normalizer/normalizer-valid.test.js +233 -0
  266. package/dist/tests/normalizer/utils.d.ts +18 -0
  267. package/dist/tests/normalizer/utils.js +36 -0
  268. package/dist/tests/optimizer/compress-references.test.d.ts +1 -0
  269. package/dist/tests/optimizer/compress-references.test.js +299 -0
  270. package/dist/tests/optimizer/deduplication.test.d.ts +1 -0
  271. package/dist/tests/optimizer/deduplication.test.js +127 -0
  272. package/dist/tests/optimizer/integration.test.d.ts +1 -0
  273. package/dist/tests/optimizer/integration.test.js +126 -0
  274. package/dist/tests/optimizer/optimization-report.test.d.ts +1 -0
  275. package/dist/tests/optimizer/optimization-report.test.js +217 -0
  276. package/dist/tests/optimizer/optimize-document.test.d.ts +1 -0
  277. package/dist/tests/optimizer/optimize-document.test.js +182 -0
  278. package/dist/tests/optimizer/orphaned-schemas.test.d.ts +1 -0
  279. package/dist/tests/optimizer/orphaned-schemas.test.js +189 -0
  280. package/dist/tests/optimizer/sort-schemas.test.d.ts +1 -0
  281. package/dist/tests/optimizer/sort-schemas.test.js +126 -0
  282. package/dist/tests/optimizer/utils.d.ts +8 -0
  283. package/dist/tests/optimizer/utils.js +199 -0
  284. package/dist/tests/schemas/schemas-edge-cases.test.d.ts +1 -0
  285. package/dist/tests/schemas/schemas-edge-cases.test.js +218 -0
  286. package/dist/tests/schemas/schemas.test.d.ts +1 -0
  287. package/dist/tests/schemas/schemas.test.js +395 -0
  288. package/dist/tests/schemas/utils.d.ts +2 -0
  289. package/dist/tests/schemas/utils.js +3 -0
  290. package/dist/tests/utils.d.ts +10 -0
  291. package/dist/tests/utils.js +118 -0
  292. package/dist/tests/validator/config-validator.test.d.ts +1 -0
  293. package/dist/tests/validator/config-validator.test.js +73 -0
  294. package/dist/tests/validator/debug-config.d.ts +0 -0
  295. package/dist/tests/validator/debug-config.js +1 -0
  296. package/dist/tests/validator/debug-missing-service.d.ts +0 -0
  297. package/dist/tests/validator/debug-missing-service.js +1 -0
  298. package/dist/tests/validator/debug-other-configs.d.ts +0 -0
  299. package/dist/tests/validator/debug-other-configs.js +1 -0
  300. package/dist/tests/validator/debug-references.d.ts +0 -0
  301. package/dist/tests/validator/debug-references.js +1 -0
  302. package/dist/tests/validator/unispec-validator.test.d.ts +1 -0
  303. package/dist/tests/validator/unispec-validator.test.js +98 -0
  304. package/dist/tests/validator/utils.d.ts +6 -0
  305. package/dist/tests/validator/utils.js +20 -0
  306. package/package.json +4 -3
@@ -0,0 +1,336 @@
1
+ import assert from "node:assert";
2
+ import fs from "node:fs";
3
+ import { describe, it } from "node:test";
4
+ import { getExamplePath } from "../../tests/utils.js";
5
+ import { getYamlModule, loadUniSpec, validateDocumentSecurity, validateYamlModule, } from "../../src/loader/index.js";
6
+ describe("loader", () => {
7
+ describe("loadUniSpec", () => {
8
+ it("should load valid JSON UniSpec document", async () => {
9
+ const validSpecPath = getExamplePath("valid", "spec", "rest-simple.json");
10
+ const jsonContent = fs.readFileSync(validSpecPath, "utf-8");
11
+ const result = await loadUniSpec(jsonContent);
12
+ assert.strictEqual(result.unispecVersion, "1.0.0");
13
+ assert.strictEqual(result.service.name, "user-service");
14
+ assert.strictEqual(result.service.protocols?.rest?.routes?.length, 2);
15
+ });
16
+ it("should load valid UniSpec document as object", async () => {
17
+ const validSpec = {
18
+ unispecVersion: "1.0.0",
19
+ service: {
20
+ name: "test-service",
21
+ description: "Test service",
22
+ protocols: {
23
+ rest: {
24
+ routes: [
25
+ {
26
+ name: "testRoute",
27
+ path: "/test",
28
+ method: "GET",
29
+ responses: {
30
+ "200": { description: "OK" },
31
+ },
32
+ },
33
+ ],
34
+ },
35
+ },
36
+ },
37
+ };
38
+ const result = await loadUniSpec(validSpec);
39
+ assert.strictEqual(result.service.name, "test-service");
40
+ assert.strictEqual(result.unispecVersion, "1.0.0");
41
+ });
42
+ it("should load valid YAML UniSpec document", async () => {
43
+ const yamlContent = `
44
+ unispecVersion: "1.0.0"
45
+ service:
46
+ name: "yaml-service"
47
+ description: "YAML based service"
48
+ protocols:
49
+ rest:
50
+ routes:
51
+ - name: "getUsers"
52
+ path: "/users"
53
+ method: "GET"
54
+ responses:
55
+ "200":
56
+ description: "Success"
57
+ `;
58
+ const result = await loadUniSpec(yamlContent);
59
+ assert.strictEqual(result.service.name, "yaml-service");
60
+ assert.strictEqual(result.unispecVersion, "1.0.0");
61
+ });
62
+ it("should reject empty string input", async () => {
63
+ try {
64
+ await loadUniSpec(" ");
65
+ assert.fail("Should have thrown an error");
66
+ }
67
+ catch (error) {
68
+ assert.ok(error instanceof Error);
69
+ assert.ok(error.message.includes("empty"));
70
+ }
71
+ });
72
+ it("should reject invalid JSON and YAML", async () => {
73
+ const invalidContent = "{ invalid json syntax: [unclosed array";
74
+ try {
75
+ await loadUniSpec(invalidContent);
76
+ assert.fail("Should have thrown an error");
77
+ }
78
+ catch (error) {
79
+ assert.ok(error instanceof Error);
80
+ assert.ok(error.message.includes("Failed to parse"));
81
+ }
82
+ });
83
+ it("should enforce document size limit", async () => {
84
+ const largeContent = "x".repeat(11 * 1024 * 1024); // 11MB
85
+ try {
86
+ await loadUniSpec(largeContent, { maxDocumentSize: 10 * 1024 * 1024 });
87
+ assert.fail("Should have thrown an error");
88
+ }
89
+ catch (error) {
90
+ assert.ok(error instanceof Error);
91
+ assert.ok(error.message.includes("Document size"));
92
+ }
93
+ });
94
+ it("should load valid examples from schema package", async () => {
95
+ const validExamples = [
96
+ "valid/spec/rest-simple.json",
97
+ "valid/spec/graphql-simple.json",
98
+ "valid/spec/websocket-simple.json",
99
+ "valid/spec/mixed-complete.json",
100
+ ];
101
+ for (const example of validExamples) {
102
+ const examplePath = getExamplePath(...example.split("/"));
103
+ const content = fs.readFileSync(examplePath, "utf-8");
104
+ const result = await loadUniSpec(content);
105
+ assert.ok(result.unispecVersion);
106
+ assert.ok(result.service.name);
107
+ assert.ok(result.service.protocols);
108
+ }
109
+ });
110
+ it("should handle invalid examples appropriately", async () => {
111
+ const invalidExamples = [
112
+ "invalid/spec/missing-service-name.json",
113
+ "invalid/spec/missing-unispec-version.json",
114
+ "invalid/spec/invalid-identifier.json",
115
+ ];
116
+ for (const example of invalidExamples) {
117
+ const examplePath = getExamplePath(...example.split("/"));
118
+ const content = fs.readFileSync(examplePath, "utf-8");
119
+ // Note: loader only handles parsing, not validation
120
+ // Invalid schema examples should still parse as JSON/YAML
121
+ const result = await loadUniSpec(content);
122
+ // Should parse successfully but validation errors would be caught elsewhere
123
+ assert.ok(typeof result === "object");
124
+ }
125
+ });
126
+ });
127
+ describe("validateDocumentSecurity", () => {
128
+ const defaultOptions = {
129
+ maxDepth: 100,
130
+ maxKeys: 10000,
131
+ allowedTags: ["str", "int", "float", "bool", "null", "seq", "map"],
132
+ maxDocumentSize: 10 * 1024 * 1024,
133
+ strictYamlTags: false,
134
+ };
135
+ it("should pass validation for normal documents", () => {
136
+ const doc = {
137
+ level1: {
138
+ level2: {
139
+ level3: "value",
140
+ },
141
+ },
142
+ };
143
+ validateDocumentSecurity(doc, defaultOptions);
144
+ // Should not throw
145
+ });
146
+ it("should reject documents exceeding max depth", () => {
147
+ const doc = {};
148
+ let current = doc;
149
+ // Create nested structure exceeding max depth
150
+ for (let i = 0; i < 105; i++) {
151
+ current.next = {};
152
+ current = current.next;
153
+ }
154
+ try {
155
+ validateDocumentSecurity(doc, { ...defaultOptions, maxDepth: 100 });
156
+ assert.fail("Should have thrown an error");
157
+ }
158
+ catch (error) {
159
+ assert.ok(error instanceof Error);
160
+ assert.ok(error.message.includes("depth"));
161
+ }
162
+ });
163
+ it("should reject documents exceeding max keys", () => {
164
+ const doc = {};
165
+ // Create object with many keys
166
+ for (let i = 0; i < 105; i++) {
167
+ doc[`key${i}`] = `value${i}`;
168
+ }
169
+ try {
170
+ validateDocumentSecurity(doc, { ...defaultOptions, maxKeys: 100 });
171
+ assert.fail("Should have thrown an error");
172
+ }
173
+ catch (error) {
174
+ assert.ok(error instanceof Error);
175
+ assert.ok(error.message.includes("key count"));
176
+ }
177
+ });
178
+ it("should handle arrays correctly", () => {
179
+ const doc = {
180
+ array: [{ item: 1 }, { item: 2 }, { nested: { deep: "value" } }],
181
+ };
182
+ validateDocumentSecurity(doc, defaultOptions);
183
+ // Should not throw
184
+ });
185
+ it("should handle mixed structures", () => {
186
+ const doc = {
187
+ strings: ["a", "b", "c"],
188
+ objects: {
189
+ nested: {
190
+ array: [1, 2, 3],
191
+ },
192
+ },
193
+ number: 42,
194
+ boolean: true,
195
+ null: null,
196
+ };
197
+ validateDocumentSecurity(doc, defaultOptions);
198
+ // Should not throw
199
+ });
200
+ });
201
+ describe("getYamlModule", () => {
202
+ it("should load and validate YAML module", async () => {
203
+ const yamlModule = await getYamlModule();
204
+ assert.ok(yamlModule);
205
+ assert.strictEqual(typeof yamlModule.load, "function");
206
+ assert.ok(yamlModule.FAILSAFE_SCHEMA);
207
+ });
208
+ it("should cache YAML module", async () => {
209
+ const module1 = await getYamlModule();
210
+ const module2 = await getYamlModule();
211
+ assert.strictEqual(module1, module2);
212
+ });
213
+ });
214
+ describe("validateYamlModule", () => {
215
+ it("should validate correct YAML module", () => {
216
+ const mockYamlModule = {
217
+ load: () => { },
218
+ FAILSAFE_SCHEMA: {},
219
+ other: "property",
220
+ };
221
+ // Should not throw
222
+ validateYamlModule(mockYamlModule);
223
+ });
224
+ it("should reject non-object modules", () => {
225
+ try {
226
+ validateYamlModule("not an object");
227
+ assert.fail("Should have thrown an error");
228
+ }
229
+ catch (error) {
230
+ assert.ok(error instanceof Error);
231
+ assert.ok(error.message.includes("must be an object"));
232
+ }
233
+ });
234
+ it("should reject modules without load function", () => {
235
+ const invalidModule = {
236
+ FAILSAFE_SCHEMA: {},
237
+ };
238
+ try {
239
+ validateYamlModule(invalidModule);
240
+ assert.fail("Should have thrown an error");
241
+ }
242
+ catch (error) {
243
+ assert.ok(error instanceof Error);
244
+ assert.ok(error.message.includes("missing load function"));
245
+ }
246
+ });
247
+ it("should reject modules without FAILSAFE_SCHEMA", () => {
248
+ const invalidModule = {
249
+ load: () => { },
250
+ };
251
+ try {
252
+ validateYamlModule(invalidModule);
253
+ assert.fail("Should have thrown an error");
254
+ }
255
+ catch (error) {
256
+ assert.ok(error instanceof Error);
257
+ assert.ok(error.message.includes("FAILSAFE_SCHEMA"));
258
+ }
259
+ });
260
+ });
261
+ describe("security constraints", () => {
262
+ it("should respect custom security options", async () => {
263
+ const doc = {
264
+ unispecVersion: "1.0.0",
265
+ service: {
266
+ name: "test",
267
+ protocols: {},
268
+ },
269
+ };
270
+ // Should work with relaxed constraints
271
+ await loadUniSpec(doc, {
272
+ maxDepth: 1000,
273
+ maxKeys: 100000,
274
+ maxDocumentSize: 100 * 1024 * 1024,
275
+ });
276
+ });
277
+ it("should handle circular references gracefully", async () => {
278
+ const doc = { name: "test" };
279
+ doc.self = doc;
280
+ try {
281
+ await loadUniSpec(doc);
282
+ // Circular references in JavaScript objects are handled by the security validation
283
+ // which uses iteration instead of recursion
284
+ }
285
+ catch (error) {
286
+ // Should not cause stack overflow
287
+ assert.ok(error instanceof Error);
288
+ assert.ok(!error.message.includes("stack"));
289
+ }
290
+ });
291
+ });
292
+ describe("edge cases", () => {
293
+ it("should handle null and undefined values", async () => {
294
+ const doc = {
295
+ unispecVersion: "1.0.0",
296
+ service: {
297
+ name: "test",
298
+ description: null,
299
+ tags: undefined,
300
+ protocols: {},
301
+ },
302
+ };
303
+ const result = await loadUniSpec(doc);
304
+ assert.strictEqual(result.service.name, "test");
305
+ assert.strictEqual(result.service.description, null);
306
+ });
307
+ it("should handle empty objects and arrays", async () => {
308
+ const doc = {
309
+ unispecVersion: "1.0.0",
310
+ service: {
311
+ name: "test",
312
+ protocols: {
313
+ rest: {
314
+ routes: [],
315
+ schemas: {},
316
+ },
317
+ },
318
+ },
319
+ };
320
+ const result = await loadUniSpec(doc);
321
+ assert.strictEqual(result.service.protocols?.rest?.routes?.length, 0);
322
+ });
323
+ it("should handle special characters in strings", async () => {
324
+ const doc = {
325
+ unispecVersion: "1.0.0",
326
+ service: {
327
+ name: "test-service-特殊字符-🚀",
328
+ description: 'Description with "quotes" and \n newlines',
329
+ protocols: {},
330
+ },
331
+ };
332
+ const result = await loadUniSpec(doc);
333
+ assert.strictEqual(result.service.name, "test-service-特殊字符-🚀");
334
+ });
335
+ });
336
+ });