ts-openapi-codegen 2.1.0-beta.8 → 2.1.0-beta.9

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 (133) hide show
  1. package/README.md +4 -0
  2. package/README.rus.md +4 -0
  3. package/dist/cli/analyzeDiff/__tests__/analyzeDiff.cli.test.js +31 -24
  4. package/dist/cli/analyzeDiff/__tests__/analyzeDiffLomMiracles.test.d.ts +2 -0
  5. package/dist/cli/analyzeDiff/__tests__/analyzeDiffLomMiracles.test.d.ts.map +1 -0
  6. package/dist/cli/analyzeDiff/__tests__/analyzeDiffLomMiracles.test.js +47 -0
  7. package/dist/cli/analyzeDiff/__tests__/analyzeDiffRenameAndInvalidRegex.test.js +8 -7
  8. package/dist/cli/analyzeDiff/__tests__/analyzeDiffTypeCoercion.test.js +8 -7
  9. package/dist/cli/analyzeDiff/analyzeDiff.d.ts +14 -2
  10. package/dist/cli/analyzeDiff/analyzeDiff.d.ts.map +1 -1
  11. package/dist/cli/analyzeDiff/analyzeDiff.js +56 -13
  12. package/dist/cli/analyzeDiff/ciSummary.d.ts +6 -3
  13. package/dist/cli/analyzeDiff/ciSummary.d.ts.map +1 -1
  14. package/dist/cli/analyzeDiff/ciSummary.js +10 -6
  15. package/dist/cli/analyzeDiff/report.d.ts +0 -1
  16. package/dist/cli/analyzeDiff/report.d.ts.map +1 -1
  17. package/dist/cli/analyzeDiff/report.js +1 -3
  18. package/dist/cli/analyzeDiff/writeLegacyReport.d.ts +2 -0
  19. package/dist/cli/analyzeDiff/writeLegacyReport.d.ts.map +1 -1
  20. package/dist/cli/analyzeDiff/writeLegacyReport.js +2 -0
  21. package/dist/cli/analyzeUsage/core/Scanner.d.ts +8 -0
  22. package/dist/cli/analyzeUsage/core/Scanner.d.ts.map +1 -1
  23. package/dist/cli/analyzeUsage/core/Scanner.js +10 -0
  24. package/dist/cli/analyzeUsage/rules/ClientRule.d.ts +8 -0
  25. package/dist/cli/analyzeUsage/rules/ClientRule.d.ts.map +1 -1
  26. package/dist/cli/analyzeUsage/rules/ClientRule.js +10 -0
  27. package/dist/cli/analyzeUsage/rules/ServiceRule.d.ts +8 -0
  28. package/dist/cli/analyzeUsage/rules/ServiceRule.d.ts.map +1 -1
  29. package/dist/cli/analyzeUsage/rules/ServiceRule.js +10 -0
  30. package/dist/common/LoggerMessages.d.ts +5 -0
  31. package/dist/common/LoggerMessages.d.ts.map +1 -1
  32. package/dist/common/LoggerMessages.js +4 -0
  33. package/dist/core/OpenApiClient.d.ts +8 -0
  34. package/dist/core/OpenApiClient.d.ts.map +1 -1
  35. package/dist/core/OpenApiClient.js +16 -2
  36. package/dist/core/WriteClient.d.ts +52 -15
  37. package/dist/core/WriteClient.d.ts.map +1 -1
  38. package/dist/core/WriteClient.js +36 -4
  39. package/dist/core/semanticDiff/__tests__/analyzeOpenApiDiff.test.js +72 -0
  40. package/dist/core/semanticDiff/__tests__/semanticDiffReportSchema.test.js +20 -1
  41. package/dist/core/semanticDiff/analyzeOpenApiDiff.d.ts +58 -6
  42. package/dist/core/semanticDiff/analyzeOpenApiDiff.d.ts.map +1 -1
  43. package/dist/core/semanticDiff/analyzeOpenApiDiff.js +47 -19
  44. package/dist/core/semanticDiff/semanticDiffReportSchema.d.ts +11 -1
  45. package/dist/core/semanticDiff/semanticDiffReportSchema.d.ts.map +1 -1
  46. package/dist/core/semanticDiff/semanticDiffReportSchema.js +140 -50
  47. package/dist/core/types/DiffReport.model.d.ts +101 -0
  48. package/dist/core/types/DiffReport.model.d.ts.map +1 -0
  49. package/dist/core/types/DiffReport.model.js +5 -0
  50. package/dist/core/types/shared/Model.model.d.ts +36 -0
  51. package/dist/core/types/shared/Model.model.d.ts.map +1 -1
  52. package/dist/core/utils/__tests__/applyDiffReportToClient.test.js +182 -0
  53. package/dist/core/utils/__tests__/buildMiraclesFromSemanticChanges.test.d.ts +2 -0
  54. package/dist/core/utils/__tests__/buildMiraclesFromSemanticChanges.test.d.ts.map +1 -0
  55. package/dist/core/utils/__tests__/buildMiraclesFromSemanticChanges.test.js +77 -0
  56. package/dist/core/utils/__tests__/expandOpenApiRefsForSemanticDiff.test.d.ts +2 -0
  57. package/dist/core/utils/__tests__/expandOpenApiRefsForSemanticDiff.test.d.ts.map +1 -0
  58. package/dist/core/utils/__tests__/expandOpenApiRefsForSemanticDiff.test.js +159 -0
  59. package/dist/core/utils/__tests__/loadDiffReport.test.js +131 -0
  60. package/dist/core/utils/__tests__/modelHelpers.test.js +27 -9
  61. package/dist/core/utils/__tests__/prepareDtoModels.test.js +74 -2
  62. package/dist/core/utils/__tests__/resolveClassesModeTypes.test.d.ts +2 -0
  63. package/dist/core/utils/__tests__/resolveClassesModeTypes.test.d.ts.map +1 -0
  64. package/dist/core/utils/__tests__/resolveClassesModeTypes.test.js +111 -0
  65. package/dist/core/utils/__tests__/semanticChangesToDiffEntries.test.d.ts +2 -0
  66. package/dist/core/utils/__tests__/semanticChangesToDiffEntries.test.d.ts.map +1 -0
  67. package/dist/core/utils/__tests__/semanticChangesToDiffEntries.test.js +68 -0
  68. package/dist/core/utils/__tests__/serviceHelpers.test.js +10 -11
  69. package/dist/core/utils/__tests__/templateRendering.test.js +71 -0
  70. package/dist/core/utils/adapters/__tests__/semanticToStructural.test.d.ts +2 -0
  71. package/dist/core/utils/adapters/__tests__/semanticToStructural.test.d.ts.map +1 -0
  72. package/dist/core/utils/adapters/__tests__/semanticToStructural.test.js +63 -0
  73. package/dist/core/utils/adapters/extractMiraclesFromSemantic.d.ts +10 -0
  74. package/dist/core/utils/adapters/extractMiraclesFromSemantic.d.ts.map +1 -0
  75. package/dist/core/utils/adapters/extractMiraclesFromSemantic.js +13 -0
  76. package/dist/core/utils/adapters/index.d.ts +4 -0
  77. package/dist/core/utils/adapters/index.d.ts.map +1 -0
  78. package/dist/core/utils/adapters/index.js +8 -0
  79. package/dist/core/utils/adapters/semanticToStructural.d.ts +12 -0
  80. package/dist/core/utils/adapters/semanticToStructural.d.ts.map +1 -0
  81. package/dist/core/utils/adapters/semanticToStructural.js +36 -0
  82. package/dist/core/utils/applyDiffReportToClient.d.ts +13 -1
  83. package/dist/core/utils/applyDiffReportToClient.d.ts.map +1 -1
  84. package/dist/core/utils/applyDiffReportToClient.js +187 -107
  85. package/dist/core/utils/buildMiraclesFromSemanticChanges.d.ts +25 -0
  86. package/dist/core/utils/buildMiraclesFromSemanticChanges.d.ts.map +1 -0
  87. package/dist/core/utils/buildMiraclesFromSemanticChanges.js +146 -0
  88. package/dist/core/utils/expandOpenApiRefsForSemanticDiff.d.ts +23 -0
  89. package/dist/core/utils/expandOpenApiRefsForSemanticDiff.d.ts.map +1 -0
  90. package/dist/core/utils/expandOpenApiRefsForSemanticDiff.js +163 -0
  91. package/dist/core/utils/getOpenApiSpec.d.ts +18 -0
  92. package/dist/core/utils/getOpenApiSpec.d.ts.map +1 -1
  93. package/dist/core/utils/getOpenApiSpec.js +35 -0
  94. package/dist/core/utils/loadDiffReport.d.ts +11 -30
  95. package/dist/core/utils/loadDiffReport.d.ts.map +1 -1
  96. package/dist/core/utils/loadDiffReport.js +69 -3
  97. package/dist/core/utils/loadSemanticOpenApiSpec.d.ts +15 -0
  98. package/dist/core/utils/loadSemanticOpenApiSpec.d.ts.map +1 -0
  99. package/dist/core/utils/loadSemanticOpenApiSpec.js +61 -0
  100. package/dist/core/utils/modelHelpers.d.ts +13 -5
  101. package/dist/core/utils/modelHelpers.d.ts.map +1 -1
  102. package/dist/core/utils/modelHelpers.js +28 -23
  103. package/dist/core/utils/prepareDtoModels.d.ts +5 -0
  104. package/dist/core/utils/prepareDtoModels.d.ts.map +1 -1
  105. package/dist/core/utils/prepareDtoModels.js +55 -12
  106. package/dist/core/utils/resolveClassesModeTypes.d.ts +8 -0
  107. package/dist/core/utils/resolveClassesModeTypes.d.ts.map +1 -0
  108. package/dist/core/utils/resolveClassesModeTypes.js +77 -0
  109. package/dist/core/utils/semanticChangesToDiffEntries.d.ts +37 -0
  110. package/dist/core/utils/semanticChangesToDiffEntries.d.ts.map +1 -0
  111. package/dist/core/utils/semanticChangesToDiffEntries.js +99 -0
  112. package/dist/core/utils/semanticPointerToJsonPath.d.ts +7 -0
  113. package/dist/core/utils/semanticPointerToJsonPath.d.ts.map +1 -0
  114. package/dist/core/utils/semanticPointerToJsonPath.js +67 -0
  115. package/dist/core/utils/serviceHelpers.d.ts +6 -7
  116. package/dist/core/utils/serviceHelpers.d.ts.map +1 -1
  117. package/dist/core/utils/serviceHelpers.js +8 -25
  118. package/dist/core/utils/writeClientServices.d.ts +14 -14
  119. package/dist/core/utils/writeClientServices.d.ts.map +1 -1
  120. package/dist/core/utils/writeClientServices.js +4 -8
  121. package/dist/templatesCompiled/client/exportModels.d.ts +17 -11
  122. package/dist/templatesCompiled/client/exportModels.d.ts.map +1 -1
  123. package/dist/templatesCompiled/client/exportModels.js +96 -49
  124. package/dist/templatesCompiled/client/exportService.d.ts +13 -10
  125. package/dist/templatesCompiled/client/exportService.d.ts.map +1 -1
  126. package/dist/templatesCompiled/client/exportService.js +95 -67
  127. package/package.json +1 -3
  128. package/dist/cli/analyzeDiff/buildLegacyReport.d.ts +0 -17
  129. package/dist/cli/analyzeDiff/buildLegacyReport.d.ts.map +0 -1
  130. package/dist/cli/analyzeDiff/buildLegacyReport.js +0 -54
  131. package/dist/cli/analyzeDiff/diffEngine.d.ts +0 -54
  132. package/dist/cli/analyzeDiff/diffEngine.d.ts.map +0 -1
  133. package/dist/cli/analyzeDiff/diffEngine.js +0 -209
@@ -1,7 +1,15 @@
1
1
  import { GovernancePolicyConfig, GovernanceReport } from '../governance/evaluateGovernanceRules';
2
+ import type { UnifiedDiffReport } from '../types/DiffReport.model';
2
3
  import { CommonOpenApi } from '../types/shared/CommonOpenApi.model';
4
+ import type { MiracleEntry } from '../types/shared/Miracle.model';
3
5
  type ChangeSeverity = 'breaking' | 'non-breaking' | 'informational';
4
- type SemanticDiffSummary = {
6
+ /**
7
+ * Сводка семантических изменений по уровню серьёзности.
8
+ * @property breaking количество breaking-изменений
9
+ * @property nonBreaking количество обратно совместимых изменений
10
+ * @property informational количество информационных изменений
11
+ */
12
+ export type SemanticDiffSummary = {
5
13
  breaking: number;
6
14
  nonBreaking: number;
7
15
  informational: number;
@@ -9,37 +17,81 @@ type SemanticDiffSummary = {
9
17
  type SemanticDiffSemverRecommendation = 'major' | 'minor' | 'patch';
10
18
  type SemanticDiffConfidence = 'high' | 'medium' | 'low';
11
19
  type SemanticDiffRecommendationReason = 'HAS_BREAKING_CHANGES' | 'HAS_BACKWARD_COMPATIBLE_CHANGES' | 'HAS_INFORMATIONAL_ONLY_CHANGES' | 'NO_API_SURFACE_CHANGES';
12
- type SemanticDiffRecommendation = {
20
+ /**
21
+ * Рекомендация по semver-версии на основе семантического diff.
22
+ * @property semver рекомендуемый уровень версии
23
+ * @property confidence уверенность в рекомендации
24
+ * @property reason человекочитаемое объяснение
25
+ * @property reasons машиночитаемые коды причин
26
+ */
27
+ export type SemanticDiffRecommendation = {
13
28
  semver: SemanticDiffSemverRecommendation;
14
29
  confidence: SemanticDiffConfidence;
15
30
  reason: string;
16
31
  reasons: SemanticDiffRecommendationReason[];
17
32
  };
18
- type SemanticDiffChange = {
33
+ /**
34
+ * Одно семантическое изменение OpenAPI.
35
+ * @property type тип изменения
36
+ * @property severity уровень серьёзности
37
+ * @property message описание изменения
38
+ * @property path JSON Pointer путь к изменённому элементу
39
+ * @property [from] значение до изменения
40
+ * @property [to] значение после изменения
41
+ * @property [fromRequired] обязательность до изменения
42
+ * @property [toRequired] обязательность после изменения
43
+ * @property [fromNullable] nullable до изменения
44
+ * @property [toNullable] nullable после изменения
45
+ */
46
+ export type SemanticDiffChange = {
19
47
  type: string;
20
48
  severity: ChangeSeverity;
21
49
  message: string;
22
50
  path: string;
51
+ from?: unknown;
52
+ to?: unknown;
53
+ fromRequired?: boolean;
54
+ toRequired?: boolean;
55
+ fromNullable?: boolean;
56
+ toNullable?: boolean;
23
57
  };
58
+ /** Версия схемы семантического diff-отчёта. */
24
59
  export declare const SEMANTIC_DIFF_REPORT_SCHEMA_VERSION = "1.1.0";
60
+ /**
61
+ * Семантический diff-отчёт OpenAPI.
62
+ * @property schemaVersion версия схемы отчёта
63
+ * @property summary сводка изменений по серьёзности
64
+ * @property recommendation рекомендация по semver
65
+ * @property governance результат проверки governance-правил
66
+ * @property changes список семантических изменений
67
+ * @property [miracles] кандидаты на переименование и приведение типов
68
+ */
25
69
  export type SemanticDiffReport = {
26
70
  schemaVersion: string;
27
71
  summary: SemanticDiffSummary;
28
72
  recommendation: SemanticDiffRecommendation;
29
73
  governance: GovernanceReport;
30
74
  changes: SemanticDiffChange[];
75
+ miracles?: MiracleEntry[];
31
76
  };
32
77
  type AnalyzeOpenApiDiffOptions = {
33
78
  allowBreaking?: boolean;
34
79
  governanceConfig?: GovernancePolicyConfig;
35
80
  };
36
81
  /**
37
- * Creates semantic diff report between two OpenAPI specs.
82
+ * Формирует семантический diff-отчёт между двумя OpenAPI-спецификациями.
83
+ * @param oldSpec базовая спецификация
84
+ * @param newSpec целевая спецификация
85
+ * @param [options] опции анализа, включая governance и разрешение breaking-изменений
86
+ * @returns семантический diff-отчёт
38
87
  */
39
88
  export declare function analyzeOpenApiDiff(oldSpec: CommonOpenApi, newSpec: CommonOpenApi, options?: AnalyzeOpenApiDiffOptions): SemanticDiffReport;
40
89
  /**
41
- * Writes semantic diff report to JSON file and returns absolute path.
90
+ * Записывает семантический или унифицированный diff-отчёт в JSON-файл.
91
+ * @param report отчёт для сохранения
92
+ * @param reportFilePath путь к файлу отчёта
93
+ * @returns абсолютный путь к сохранённому файлу
42
94
  */
43
- export declare function writeSemanticDiffReport(report: SemanticDiffReport, reportFilePath: string): Promise<string>;
95
+ export declare function writeSemanticDiffReport(report: SemanticDiffReport | UnifiedDiffReport, reportFilePath: string): Promise<string>;
44
96
  export {};
45
97
  //# sourceMappingURL=analyzeOpenApiDiff.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"analyzeOpenApiDiff.d.ts","sourceRoot":"","sources":["../../../src/core/semanticDiff/analyzeOpenApiDiff.ts"],"names":[],"mappings":"AAKA,OAAO,EAA2B,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAC1H,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEpE,KAAK,cAAc,GAAG,UAAU,GAAG,cAAc,GAAG,eAAe,CAAC;AAEpE,KAAK,mBAAmB,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,KAAK,gCAAgC,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AACpE,KAAK,sBAAsB,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AACxD,KAAK,gCAAgC,GAAG,sBAAsB,GAAG,iCAAiC,GAAG,gCAAgC,GAAG,wBAAwB,CAAC;AAEjK,KAAK,0BAA0B,GAAG;IAC9B,MAAM,EAAE,gCAAgC,CAAC;IACzC,UAAU,EAAE,sBAAsB,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gCAAgC,EAAE,CAAC;CAC/C,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,mCAAmC,UAAU,CAAC;AAE3D,MAAM,MAAM,kBAAkB,GAAG;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,cAAc,EAAE,0BAA0B,CAAC;IAC3C,UAAU,EAAE,gBAAgB,CAAC;IAC7B,OAAO,EAAE,kBAAkB,EAAE,CAAC;CACjC,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;CAC7C,CAAC;AAuxBF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,GAAE,yBAA8B,GAAG,kBAAkB,CA2B9I;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAajH"}
1
+ {"version":3,"file":"analyzeOpenApiDiff.d.ts","sourceRoot":"","sources":["../../../src/core/semanticDiff/analyzeOpenApiDiff.ts"],"names":[],"mappings":"AAKA,OAAO,EAA2B,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAC1H,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,KAAK,cAAc,GAAG,UAAU,GAAG,cAAc,GAAG,eAAe,CAAC;AAEpE;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,KAAK,gCAAgC,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AACpE,KAAK,sBAAsB,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AACxD,KAAK,gCAAgC,GAAG,sBAAsB,GAAG,iCAAiC,GAAG,gCAAgC,GAAG,wBAAwB,CAAC;AAEjK;;;;;;GAMG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACrC,MAAM,EAAE,gCAAgC,CAAC;IACzC,UAAU,EAAE,sBAAsB,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gCAAgC,EAAE,CAAC;CAC/C,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAIF,+CAA+C;AAC/C,eAAO,MAAM,mCAAmC,UAAU,CAAC;AAE3D;;;;;;;;GAQG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,cAAc,EAAE,0BAA0B,CAAC;IAC3C,UAAU,EAAE,gBAAgB,CAAC;IAC7B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC7B,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;CAC7C,CAAC;AA0zBF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,GAAE,yBAA8B,GAAG,kBAAkB,CA2B9I;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,kBAAkB,GAAG,iBAAiB,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAarI"}
@@ -11,6 +11,7 @@ const fileSystemHelpers_1 = require("../../common/utils/fileSystemHelpers");
11
11
  const format_1 = require("../../common/utils/format");
12
12
  const pathHelpers_1 = require("../../common/utils/pathHelpers");
13
13
  const evaluateGovernanceRules_1 = require("../governance/evaluateGovernanceRules");
14
+ /** Версия схемы семантического diff-отчёта. */
14
15
  exports.SEMANTIC_DIFF_REPORT_SCHEMA_VERSION = '1.1.0';
15
16
  const HTTP_METHODS = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'];
16
17
  /**
@@ -373,10 +374,19 @@ function buildCanonicalOperations(spec) {
373
374
  }
374
375
  }
375
376
  }
377
+ const operationId = typeof operation.operationId === 'string' ? operation.operationId : undefined;
378
+ const summary = typeof operation.summary === 'string' ? operation.summary : undefined;
379
+ const description = typeof operation.description === 'string' ? operation.description : undefined;
380
+ const tagsRaw = operation.tags;
381
+ const tags = Array.isArray(tagsRaw) ? tagsRaw.map(tag => String(tag)) : undefined;
376
382
  operations.set(operationKey, {
377
383
  parameters,
378
384
  requestBodyRequired,
379
385
  successResponses,
386
+ operationId,
387
+ summary,
388
+ description,
389
+ tags,
380
390
  });
381
391
  }
382
392
  }
@@ -385,8 +395,8 @@ function buildCanonicalOperations(spec) {
385
395
  /**
386
396
  * Pushes change entry to report collection.
387
397
  */
388
- function pushChange(changes, severity, type, path, message) {
389
- changes.push({ severity, type, path, message });
398
+ function pushChange(changes, severity, type, path, message, extras) {
399
+ changes.push({ severity, type, path, message, ...extras });
390
400
  }
391
401
  /**
392
402
  * Normalizes, deduplicates and sorts changes for stable CI output.
@@ -440,13 +450,13 @@ function diffModels(oldModels, newModels, changes) {
440
450
  }
441
451
  for (const oldPropertyName of oldModel.properties.keys()) {
442
452
  if (!newModel.properties.has(oldPropertyName)) {
443
- pushChange(changes, 'breaking', 'model.property.removed', `#/components/schemas/${modelName}/properties/${oldPropertyName}`, `Property "${oldPropertyName}" was removed from model "${modelName}".`);
453
+ pushChange(changes, 'breaking', 'model.property.removed', `#/components/schemas/${modelName}/properties/${oldPropertyName}`, `Property "${oldPropertyName}" was removed from model "${modelName}".`, { from: { type: oldModel.properties.get(oldPropertyName) } });
444
454
  }
445
455
  }
446
- for (const [newPropertyName] of newModel.properties.entries()) {
456
+ for (const [newPropertyName, newPropertyType] of newModel.properties.entries()) {
447
457
  if (!oldModel.properties.has(newPropertyName)) {
448
458
  const isRequired = newModel.required.has(newPropertyName);
449
- pushChange(changes, isRequired ? 'breaking' : 'non-breaking', 'model.property.added', `#/components/schemas/${modelName}/properties/${newPropertyName}`, `Property "${newPropertyName}" was added to model "${modelName}".`);
459
+ pushChange(changes, isRequired ? 'breaking' : 'non-breaking', 'model.property.added', `#/components/schemas/${modelName}/properties/${newPropertyName}`, `Property "${newPropertyName}" was added to model "${modelName}".`, { to: { type: newPropertyType } });
450
460
  }
451
461
  }
452
462
  for (const [propertyName, oldPropertyType] of oldModel.properties.entries()) {
@@ -456,22 +466,26 @@ function diffModels(oldModels, newModels, changes) {
456
466
  }
457
467
  if (oldPropertyType !== newPropertyType) {
458
468
  const severity = classifyTypeTransition(oldPropertyType, newPropertyType);
459
- pushChange(changes, severity, 'model.property.type.changed', `#/components/schemas/${modelName}/properties/${propertyName}`, `Property "${propertyName}" type changed in model "${modelName}" from "${oldPropertyType}" to "${newPropertyType}".`);
469
+ pushChange(changes, severity, 'model.property.type.changed', `#/components/schemas/${modelName}/properties/${propertyName}`, `Property "${propertyName}" type changed in model "${modelName}" from "${oldPropertyType}" to "${newPropertyType}".`, { from: oldPropertyType, to: newPropertyType });
460
470
  }
461
471
  const wasRequired = oldModel.required.has(propertyName);
462
472
  const isRequired = newModel.required.has(propertyName);
463
473
  if (wasRequired !== isRequired) {
464
- pushChange(changes, isRequired ? 'breaking' : 'non-breaking', 'model.property.required.changed', `#/components/schemas/${modelName}/required/${propertyName}`, `Property "${propertyName}" required flag changed in model "${modelName}" from "${wasRequired}" to "${isRequired}".`);
474
+ pushChange(changes, isRequired ? 'breaking' : 'non-breaking', 'model.property.required.changed', `#/components/schemas/${modelName}/required/${propertyName}`, `Property "${propertyName}" required flag changed in model "${modelName}" from "${wasRequired}" to "${isRequired}".`, { fromRequired: wasRequired, toRequired: isRequired });
465
475
  }
466
476
  }
467
477
  for (const oldEnumValue of oldModel.enumValues) {
468
478
  if (!newModel.enumValues.has(oldEnumValue)) {
469
- pushChange(changes, 'breaking', 'model.enum.value.removed', `#/components/schemas/${modelName}/enum`, `Enum value "${oldEnumValue}" was removed from model "${modelName}".`);
479
+ pushChange(changes, 'breaking', 'model.enum.value.removed', `#/components/schemas/${modelName}/enum`, `Enum value "${oldEnumValue}" was removed from model "${modelName}".`, {
480
+ from: oldEnumValue,
481
+ });
470
482
  }
471
483
  }
472
484
  for (const newEnumValue of newModel.enumValues) {
473
485
  if (!oldModel.enumValues.has(newEnumValue)) {
474
- pushChange(changes, 'non-breaking', 'model.enum.value.added', `#/components/schemas/${modelName}/enum`, `Enum value "${newEnumValue}" was added to model "${modelName}".`);
486
+ pushChange(changes, 'non-breaking', 'model.enum.value.added', `#/components/schemas/${modelName}/enum`, `Enum value "${newEnumValue}" was added to model "${modelName}".`, {
487
+ to: newEnumValue,
488
+ });
475
489
  }
476
490
  }
477
491
  }
@@ -480,9 +494,16 @@ function diffModels(oldModels, newModels, changes) {
480
494
  * Diffs canonical operations and appends semantic changes.
481
495
  */
482
496
  function diffOperations(oldOperations, newOperations, changes) {
483
- for (const oldOperationKey of oldOperations.keys()) {
497
+ for (const [oldOperationKey, oldOperation] of oldOperations.entries()) {
484
498
  if (!newOperations.has(oldOperationKey)) {
485
- pushChange(changes, 'breaking', 'operation.removed', `#/paths/${oldOperationKey}`, `Operation "${oldOperationKey}" was removed.`);
499
+ pushChange(changes, 'breaking', 'operation.removed', `#/paths/${oldOperationKey}`, `Operation "${oldOperationKey}" was removed.`, {
500
+ from: {
501
+ operationId: oldOperation.operationId,
502
+ summary: oldOperation.summary,
503
+ description: oldOperation.description,
504
+ tags: oldOperation.tags,
505
+ },
506
+ });
486
507
  }
487
508
  }
488
509
  for (const newOperationKey of newOperations.keys()) {
@@ -497,12 +518,12 @@ function diffOperations(oldOperations, newOperations, changes) {
497
518
  }
498
519
  for (const oldParameterName of oldOperation.parameters.keys()) {
499
520
  if (!newOperation.parameters.has(oldParameterName)) {
500
- pushChange(changes, 'breaking', 'operation.parameter.removed', `#/paths/${operationKey}/parameters/${oldParameterName}`, `Parameter "${oldParameterName}" was removed from operation "${operationKey}".`);
521
+ pushChange(changes, 'breaking', 'operation.parameter.removed', `#/paths/${operationKey}/parameters/${oldParameterName}`, `Parameter "${oldParameterName}" was removed from operation "${operationKey}".`, { from: { type: oldOperation.parameters.get(oldParameterName)?.type } });
501
522
  }
502
523
  }
503
524
  for (const [newParameterName, newParameter] of newOperation.parameters.entries()) {
504
525
  if (!oldOperation.parameters.has(newParameterName)) {
505
- pushChange(changes, newParameter.required ? 'breaking' : 'non-breaking', 'operation.parameter.added', `#/paths/${operationKey}/parameters/${newParameterName}`, `Parameter "${newParameterName}" was added to operation "${operationKey}".`);
526
+ pushChange(changes, newParameter.required ? 'breaking' : 'non-breaking', 'operation.parameter.added', `#/paths/${operationKey}/parameters/${newParameterName}`, `Parameter "${newParameterName}" was added to operation "${operationKey}".`, { to: { type: newParameter.type, required: newParameter.required } });
506
527
  }
507
528
  }
508
529
  for (const [parameterName, oldParameter] of oldOperation.parameters.entries()) {
@@ -511,15 +532,15 @@ function diffOperations(oldOperations, newOperations, changes) {
511
532
  continue;
512
533
  }
513
534
  if (oldParameter.required !== newParameter.required) {
514
- pushChange(changes, newParameter.required ? 'breaking' : 'non-breaking', 'operation.parameter.required.changed', `#/paths/${operationKey}/parameters/${parameterName}/required`, `Required flag for parameter "${parameterName}" changed in operation "${operationKey}".`);
535
+ pushChange(changes, newParameter.required ? 'breaking' : 'non-breaking', 'operation.parameter.required.changed', `#/paths/${operationKey}/parameters/${parameterName}/required`, `Required flag for parameter "${parameterName}" changed in operation "${operationKey}".`, { fromRequired: oldParameter.required, toRequired: newParameter.required });
515
536
  }
516
537
  if (oldParameter.type !== newParameter.type) {
517
538
  const severity = classifyTypeTransition(oldParameter.type, newParameter.type);
518
- pushChange(changes, severity, 'operation.parameter.type.changed', `#/paths/${operationKey}/parameters/${parameterName}/schema`, `Type for parameter "${parameterName}" changed in operation "${operationKey}" from "${oldParameter.type}" to "${newParameter.type}".`);
539
+ pushChange(changes, severity, 'operation.parameter.type.changed', `#/paths/${operationKey}/parameters/${parameterName}/schema`, `Type for parameter "${parameterName}" changed in operation "${operationKey}" from "${oldParameter.type}" to "${newParameter.type}".`, { from: oldParameter.type, to: newParameter.type });
519
540
  }
520
541
  }
521
542
  if (oldOperation.requestBodyRequired !== newOperation.requestBodyRequired) {
522
- pushChange(changes, newOperation.requestBodyRequired ? 'breaking' : 'non-breaking', 'operation.requestBody.required.changed', `#/paths/${operationKey}/requestBody/required`, `requestBody.required changed in operation "${operationKey}" from "${oldOperation.requestBodyRequired}" to "${newOperation.requestBodyRequired}".`);
543
+ pushChange(changes, newOperation.requestBodyRequired ? 'breaking' : 'non-breaking', 'operation.requestBody.required.changed', `#/paths/${operationKey}/requestBody/required`, `requestBody.required changed in operation "${operationKey}" from "${oldOperation.requestBodyRequired}" to "${newOperation.requestBodyRequired}".`, { from: oldOperation.requestBodyRequired, to: newOperation.requestBodyRequired });
523
544
  }
524
545
  for (const oldResponseCode of oldOperation.successResponses.keys()) {
525
546
  if (!newOperation.successResponses.has(oldResponseCode)) {
@@ -537,7 +558,7 @@ function diffOperations(oldOperations, newOperations, changes) {
537
558
  continue;
538
559
  }
539
560
  const severity = classifyTypeTransition(oldResponseType, newResponseType);
540
- pushChange(changes, severity, 'operation.response.success.type.changed', `#/paths/${operationKey}/responses/${responseCode}/content`, `Successful response "${responseCode}" payload type changed in operation "${operationKey}" from "${oldResponseType}" to "${newResponseType}".`);
561
+ pushChange(changes, severity, 'operation.response.success.type.changed', `#/paths/${operationKey}/responses/${responseCode}/content`, `Successful response "${responseCode}" payload type changed in operation "${operationKey}" from "${oldResponseType}" to "${newResponseType}".`, { from: oldResponseType, to: newResponseType });
541
562
  }
542
563
  }
543
564
  }
@@ -598,7 +619,11 @@ function buildSemverRecommendation(summary) {
598
619
  };
599
620
  }
600
621
  /**
601
- * Creates semantic diff report between two OpenAPI specs.
622
+ * Формирует семантический diff-отчёт между двумя OpenAPI-спецификациями.
623
+ * @param oldSpec базовая спецификация
624
+ * @param newSpec целевая спецификация
625
+ * @param [options] опции анализа, включая governance и разрешение breaking-изменений
626
+ * @returns семантический diff-отчёт
602
627
  */
603
628
  function analyzeOpenApiDiff(oldSpec, newSpec, options = {}) {
604
629
  const oldModels = buildCanonicalModels(oldSpec);
@@ -625,7 +650,10 @@ function analyzeOpenApiDiff(oldSpec, newSpec, options = {}) {
625
650
  };
626
651
  }
627
652
  /**
628
- * Writes semantic diff report to JSON file and returns absolute path.
653
+ * Записывает семантический или унифицированный diff-отчёт в JSON-файл.
654
+ * @param report отчёт для сохранения
655
+ * @param reportFilePath путь к файлу отчёта
656
+ * @returns абсолютный путь к сохранённому файлу
629
657
  */
630
658
  async function writeSemanticDiffReport(report, reportFilePath) {
631
659
  const resolvedPath = (0, pathHelpers_1.resolveHelper)(process.cwd(), reportFilePath);
@@ -1,9 +1,19 @@
1
+ import { JSONSchema7 } from 'json-schema';
2
+ /**
3
+ * Результат валидации diff-отчёта по JSON Schema.
4
+ * @property valid признак успешной валидации
5
+ * @property errors список ошибок валидации
6
+ */
1
7
  export type SemanticDiffReportSchemaValidationResult = {
2
8
  valid: boolean;
3
9
  errors: string[];
4
10
  };
11
+ /** JSON Schema контракт унифицированного diff-отчёта. */
12
+ export declare const semanticDiffReportJsonSchema: JSONSchema7;
5
13
  /**
6
- * Validates semantic diff report payload by JSON Schema contract.
14
+ * Валидирует payload diff-отчёта по JSON Schema контракту.
15
+ * @param report проверяемый отчёт
16
+ * @returns результат валидации с перечнем ошибок
7
17
  */
8
18
  export declare function validateSemanticDiffReportSchema(report: unknown): SemanticDiffReportSchemaValidationResult;
9
19
  //# sourceMappingURL=semanticDiffReportSchema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"semanticDiffReportSchema.d.ts","sourceRoot":"","sources":["../../../src/core/semanticDiff/semanticDiffReportSchema.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,wCAAwC,GAAG;IACnD,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AA4GF;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,OAAO,GAAG,wCAAwC,CAc1G"}
1
+ {"version":3,"file":"semanticDiffReportSchema.d.ts","sourceRoot":"","sources":["../../../src/core/semanticDiff/semanticDiffReportSchema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C;;;;GAIG;AACH,MAAM,MAAM,wCAAwC,GAAG;IACnD,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,4BAA4B,EAAE,WA8L1C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,OAAO,GAAG,wCAAwC,CAc1G"}
@@ -1,115 +1,205 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.semanticDiffReportJsonSchema = void 0;
3
4
  exports.validateSemanticDiffReportSchema = validateSemanticDiffReportSchema;
4
5
  const json_schema_1 = require("json-schema");
5
- const analyzeOpenApiDiff_1 = require("./analyzeOpenApiDiff");
6
- const semanticDiffReportJsonSchema = {
6
+ const DiffReport_model_1 = require("../types/DiffReport.model");
7
+ /** JSON Schema контракт унифицированного diff-отчёта. */
8
+ exports.semanticDiffReportJsonSchema = {
7
9
  type: 'object',
8
10
  additionalProperties: false,
9
11
  properties: {
10
12
  schemaVersion: {
11
13
  type: 'string',
12
- enum: [analyzeOpenApiDiff_1.SEMANTIC_DIFF_REPORT_SCHEMA_VERSION],
14
+ enum: [DiffReport_model_1.UNIFIED_DIFF_REPORT_SCHEMA_VERSION],
13
15
  required: true,
14
16
  },
15
- summary: {
17
+ timestamp: {
18
+ type: 'string',
19
+ minLength: 1,
20
+ required: true,
21
+ },
22
+ metadata: {
16
23
  type: 'object',
17
24
  additionalProperties: false,
18
25
  required: true,
19
26
  properties: {
20
- breaking: { type: 'integer', minimum: 0, required: true },
21
- nonBreaking: { type: 'integer', minimum: 0, required: true },
22
- informational: { type: 'integer', minimum: 0, required: true },
27
+ base: { type: 'string', minLength: 1, required: true },
28
+ target: { type: 'string', minLength: 1, required: true },
29
+ baseHash: { type: 'string', minLength: 1, required: true },
30
+ targetHash: { type: 'string', minLength: 1, required: true },
23
31
  },
24
32
  },
25
- recommendation: {
33
+ semantic: {
26
34
  type: 'object',
27
35
  additionalProperties: false,
28
36
  required: true,
29
37
  properties: {
30
- semver: {
31
- type: 'string',
32
- enum: ['major', 'minor', 'patch'],
38
+ summary: {
39
+ type: 'object',
40
+ additionalProperties: false,
33
41
  required: true,
42
+ properties: {
43
+ breaking: { type: 'integer', minimum: 0, required: true },
44
+ nonBreaking: { type: 'integer', minimum: 0, required: true },
45
+ informational: { type: 'integer', minimum: 0, required: true },
46
+ },
34
47
  },
35
- confidence: {
36
- type: 'string',
37
- enum: ['high', 'medium', 'low'],
48
+ recommendation: {
49
+ type: 'object',
50
+ additionalProperties: false,
38
51
  required: true,
52
+ properties: {
53
+ semver: {
54
+ type: 'string',
55
+ enum: ['major', 'minor', 'patch'],
56
+ required: true,
57
+ },
58
+ confidence: {
59
+ type: 'string',
60
+ enum: ['high', 'medium', 'low'],
61
+ required: true,
62
+ },
63
+ reason: {
64
+ type: 'string',
65
+ minLength: 1,
66
+ required: true,
67
+ },
68
+ reasons: {
69
+ type: 'array',
70
+ minItems: 1,
71
+ required: true,
72
+ items: {
73
+ type: 'string',
74
+ enum: ['HAS_BREAKING_CHANGES', 'HAS_BACKWARD_COMPATIBLE_CHANGES', 'HAS_INFORMATIONAL_ONLY_CHANGES', 'NO_API_SURFACE_CHANGES'],
75
+ },
76
+ },
77
+ },
39
78
  },
40
- reason: {
41
- type: 'string',
42
- minLength: 1,
79
+ governance: {
80
+ type: 'object',
81
+ additionalProperties: false,
43
82
  required: true,
83
+ properties: {
84
+ summary: {
85
+ type: 'object',
86
+ additionalProperties: false,
87
+ required: true,
88
+ properties: {
89
+ errors: { type: 'integer', minimum: 0, required: true },
90
+ warnings: { type: 'integer', minimum: 0, required: true },
91
+ info: { type: 'integer', minimum: 0, required: true },
92
+ },
93
+ },
94
+ violations: {
95
+ type: 'array',
96
+ required: true,
97
+ items: {
98
+ type: 'object',
99
+ additionalProperties: false,
100
+ properties: {
101
+ ruleId: { type: 'string', minLength: 1, required: true },
102
+ severity: {
103
+ type: 'string',
104
+ enum: ['error', 'warning', 'info'],
105
+ required: true,
106
+ },
107
+ message: { type: 'string', minLength: 1, required: true },
108
+ path: { type: 'string', minLength: 1, required: true },
109
+ },
110
+ },
111
+ },
112
+ },
44
113
  },
45
- reasons: {
114
+ changes: {
46
115
  type: 'array',
47
- minItems: 1,
48
116
  required: true,
49
117
  items: {
50
- type: 'string',
51
- enum: ['HAS_BREAKING_CHANGES', 'HAS_BACKWARD_COMPATIBLE_CHANGES', 'HAS_INFORMATIONAL_ONLY_CHANGES', 'NO_API_SURFACE_CHANGES'],
118
+ type: 'object',
119
+ additionalProperties: false,
120
+ properties: {
121
+ type: { type: 'string', minLength: 1, required: true },
122
+ severity: {
123
+ type: 'string',
124
+ enum: ['breaking', 'non-breaking', 'informational'],
125
+ required: true,
126
+ },
127
+ message: { type: 'string', minLength: 1, required: true },
128
+ path: { type: 'string', minLength: 1, required: true },
129
+ from: {},
130
+ to: {},
131
+ fromRequired: { type: 'boolean' },
132
+ toRequired: { type: 'boolean' },
133
+ fromNullable: { type: 'boolean' },
134
+ toNullable: { type: 'boolean' },
135
+ },
52
136
  },
53
137
  },
54
138
  },
55
139
  },
56
- governance: {
140
+ structural: {
57
141
  type: 'object',
58
142
  additionalProperties: false,
59
143
  required: true,
60
144
  properties: {
61
- summary: {
145
+ diff: {
62
146
  type: 'object',
63
147
  additionalProperties: false,
64
148
  required: true,
65
149
  properties: {
66
- errors: { type: 'integer', minimum: 0, required: true },
67
- warnings: { type: 'integer', minimum: 0, required: true },
68
- info: { type: 'integer', minimum: 0, required: true },
150
+ breaking: { type: 'array', required: true, items: { type: 'object' } },
151
+ warnings: { type: 'array', required: true, items: { type: 'object' } },
152
+ info: { type: 'array', required: true, items: { type: 'object' } },
153
+ all: { type: 'array', required: true, items: { type: 'object' } },
69
154
  },
70
155
  },
71
- violations: {
156
+ miracles: {
72
157
  type: 'array',
73
158
  required: true,
74
159
  items: {
75
160
  type: 'object',
76
161
  additionalProperties: false,
77
162
  properties: {
78
- ruleId: { type: 'string', minLength: 1, required: true },
79
- severity: {
163
+ oldPath: { type: 'string', minLength: 1, required: true },
164
+ newPath: { type: 'string', minLength: 1, required: true },
165
+ type: {
80
166
  type: 'string',
81
- enum: ['error', 'warning', 'info'],
167
+ enum: ['RENAME', 'TYPE_COERCION'],
82
168
  required: true,
83
169
  },
84
- message: { type: 'string', minLength: 1, required: true },
85
- path: { type: 'string', minLength: 1, required: true },
170
+ confidence: { type: 'number', minimum: 0, maximum: 1, required: true },
171
+ status: {
172
+ type: 'string',
173
+ enum: ['auto-generated', 'confirmed'],
174
+ required: true,
175
+ },
176
+ modelName: { type: 'string' },
177
+ oldProperty: { type: 'string' },
178
+ newProperty: { type: 'string' },
86
179
  },
87
180
  },
88
181
  },
89
- },
90
- },
91
- changes: {
92
- type: 'array',
93
- required: true,
94
- items: {
95
- type: 'object',
96
- additionalProperties: false,
97
- properties: {
98
- type: { type: 'string', minLength: 1, required: true },
99
- severity: {
100
- type: 'string',
101
- enum: ['breaking', 'non-breaking', 'informational'],
102
- required: true,
182
+ stats: {
183
+ type: 'object',
184
+ additionalProperties: false,
185
+ required: true,
186
+ properties: {
187
+ totalChanges: { type: 'integer', minimum: 0, required: true },
188
+ added: { type: 'integer', minimum: 0, required: true },
189
+ removed: { type: 'integer', minimum: 0, required: true },
190
+ changed: { type: 'integer', minimum: 0, required: true },
191
+ ignored: { type: 'integer', minimum: 0 },
192
+ stabilityScore: { type: 'integer', minimum: 0, maximum: 100, required: true },
103
193
  },
104
- message: { type: 'string', minLength: 1, required: true },
105
- path: { type: 'string', minLength: 1, required: true },
106
194
  },
107
195
  },
108
196
  },
109
197
  },
110
198
  };
111
199
  /**
112
- * Validates semantic diff report payload by JSON Schema contract.
200
+ * Валидирует payload diff-отчёта по JSON Schema контракту.
201
+ * @param report проверяемый отчёт
202
+ * @returns результат валидации с перечнем ошибок
113
203
  */
114
204
  function validateSemanticDiffReportSchema(report) {
115
205
  if (report === null || typeof report !== 'object') {
@@ -118,7 +208,7 @@ function validateSemanticDiffReportSchema(report) {
118
208
  errors: ['root: report must be an object'],
119
209
  };
120
210
  }
121
- const result = (0, json_schema_1.validate)(report, semanticDiffReportJsonSchema);
211
+ const result = (0, json_schema_1.validate)(report, exports.semanticDiffReportJsonSchema);
122
212
  return {
123
213
  valid: result.valid,
124
214
  errors: result.errors.map(error => `${error.property}: ${error.message}`),