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.
- package/README.md +4 -0
- package/README.rus.md +4 -0
- package/dist/cli/analyzeDiff/__tests__/analyzeDiff.cli.test.js +31 -24
- package/dist/cli/analyzeDiff/__tests__/analyzeDiffLomMiracles.test.d.ts +2 -0
- package/dist/cli/analyzeDiff/__tests__/analyzeDiffLomMiracles.test.d.ts.map +1 -0
- package/dist/cli/analyzeDiff/__tests__/analyzeDiffLomMiracles.test.js +47 -0
- package/dist/cli/analyzeDiff/__tests__/analyzeDiffRenameAndInvalidRegex.test.js +8 -7
- package/dist/cli/analyzeDiff/__tests__/analyzeDiffTypeCoercion.test.js +8 -7
- package/dist/cli/analyzeDiff/analyzeDiff.d.ts +14 -2
- package/dist/cli/analyzeDiff/analyzeDiff.d.ts.map +1 -1
- package/dist/cli/analyzeDiff/analyzeDiff.js +56 -13
- package/dist/cli/analyzeDiff/ciSummary.d.ts +6 -3
- package/dist/cli/analyzeDiff/ciSummary.d.ts.map +1 -1
- package/dist/cli/analyzeDiff/ciSummary.js +10 -6
- package/dist/cli/analyzeDiff/report.d.ts +0 -1
- package/dist/cli/analyzeDiff/report.d.ts.map +1 -1
- package/dist/cli/analyzeDiff/report.js +1 -3
- package/dist/cli/analyzeDiff/writeLegacyReport.d.ts +2 -0
- package/dist/cli/analyzeDiff/writeLegacyReport.d.ts.map +1 -1
- package/dist/cli/analyzeDiff/writeLegacyReport.js +2 -0
- package/dist/cli/analyzeUsage/core/Scanner.d.ts +8 -0
- package/dist/cli/analyzeUsage/core/Scanner.d.ts.map +1 -1
- package/dist/cli/analyzeUsage/core/Scanner.js +10 -0
- package/dist/cli/analyzeUsage/rules/ClientRule.d.ts +8 -0
- package/dist/cli/analyzeUsage/rules/ClientRule.d.ts.map +1 -1
- package/dist/cli/analyzeUsage/rules/ClientRule.js +10 -0
- package/dist/cli/analyzeUsage/rules/ServiceRule.d.ts +8 -0
- package/dist/cli/analyzeUsage/rules/ServiceRule.d.ts.map +1 -1
- package/dist/cli/analyzeUsage/rules/ServiceRule.js +10 -0
- package/dist/common/LoggerMessages.d.ts +5 -0
- package/dist/common/LoggerMessages.d.ts.map +1 -1
- package/dist/common/LoggerMessages.js +4 -0
- package/dist/core/OpenApiClient.d.ts +8 -0
- package/dist/core/OpenApiClient.d.ts.map +1 -1
- package/dist/core/OpenApiClient.js +16 -2
- package/dist/core/WriteClient.d.ts +52 -15
- package/dist/core/WriteClient.d.ts.map +1 -1
- package/dist/core/WriteClient.js +36 -4
- package/dist/core/semanticDiff/__tests__/analyzeOpenApiDiff.test.js +72 -0
- package/dist/core/semanticDiff/__tests__/semanticDiffReportSchema.test.js +20 -1
- package/dist/core/semanticDiff/analyzeOpenApiDiff.d.ts +58 -6
- package/dist/core/semanticDiff/analyzeOpenApiDiff.d.ts.map +1 -1
- package/dist/core/semanticDiff/analyzeOpenApiDiff.js +47 -19
- package/dist/core/semanticDiff/semanticDiffReportSchema.d.ts +11 -1
- package/dist/core/semanticDiff/semanticDiffReportSchema.d.ts.map +1 -1
- package/dist/core/semanticDiff/semanticDiffReportSchema.js +140 -50
- package/dist/core/types/DiffReport.model.d.ts +101 -0
- package/dist/core/types/DiffReport.model.d.ts.map +1 -0
- package/dist/core/types/DiffReport.model.js +5 -0
- package/dist/core/types/shared/Model.model.d.ts +36 -0
- package/dist/core/types/shared/Model.model.d.ts.map +1 -1
- package/dist/core/utils/__tests__/applyDiffReportToClient.test.js +182 -0
- package/dist/core/utils/__tests__/buildMiraclesFromSemanticChanges.test.d.ts +2 -0
- package/dist/core/utils/__tests__/buildMiraclesFromSemanticChanges.test.d.ts.map +1 -0
- package/dist/core/utils/__tests__/buildMiraclesFromSemanticChanges.test.js +77 -0
- package/dist/core/utils/__tests__/expandOpenApiRefsForSemanticDiff.test.d.ts +2 -0
- package/dist/core/utils/__tests__/expandOpenApiRefsForSemanticDiff.test.d.ts.map +1 -0
- package/dist/core/utils/__tests__/expandOpenApiRefsForSemanticDiff.test.js +159 -0
- package/dist/core/utils/__tests__/loadDiffReport.test.js +131 -0
- package/dist/core/utils/__tests__/modelHelpers.test.js +27 -9
- package/dist/core/utils/__tests__/prepareDtoModels.test.js +74 -2
- package/dist/core/utils/__tests__/resolveClassesModeTypes.test.d.ts +2 -0
- package/dist/core/utils/__tests__/resolveClassesModeTypes.test.d.ts.map +1 -0
- package/dist/core/utils/__tests__/resolveClassesModeTypes.test.js +111 -0
- package/dist/core/utils/__tests__/semanticChangesToDiffEntries.test.d.ts +2 -0
- package/dist/core/utils/__tests__/semanticChangesToDiffEntries.test.d.ts.map +1 -0
- package/dist/core/utils/__tests__/semanticChangesToDiffEntries.test.js +68 -0
- package/dist/core/utils/__tests__/serviceHelpers.test.js +10 -11
- package/dist/core/utils/__tests__/templateRendering.test.js +71 -0
- package/dist/core/utils/adapters/__tests__/semanticToStructural.test.d.ts +2 -0
- package/dist/core/utils/adapters/__tests__/semanticToStructural.test.d.ts.map +1 -0
- package/dist/core/utils/adapters/__tests__/semanticToStructural.test.js +63 -0
- package/dist/core/utils/adapters/extractMiraclesFromSemantic.d.ts +10 -0
- package/dist/core/utils/adapters/extractMiraclesFromSemantic.d.ts.map +1 -0
- package/dist/core/utils/adapters/extractMiraclesFromSemantic.js +13 -0
- package/dist/core/utils/adapters/index.d.ts +4 -0
- package/dist/core/utils/adapters/index.d.ts.map +1 -0
- package/dist/core/utils/adapters/index.js +8 -0
- package/dist/core/utils/adapters/semanticToStructural.d.ts +12 -0
- package/dist/core/utils/adapters/semanticToStructural.d.ts.map +1 -0
- package/dist/core/utils/adapters/semanticToStructural.js +36 -0
- package/dist/core/utils/applyDiffReportToClient.d.ts +13 -1
- package/dist/core/utils/applyDiffReportToClient.d.ts.map +1 -1
- package/dist/core/utils/applyDiffReportToClient.js +187 -107
- package/dist/core/utils/buildMiraclesFromSemanticChanges.d.ts +25 -0
- package/dist/core/utils/buildMiraclesFromSemanticChanges.d.ts.map +1 -0
- package/dist/core/utils/buildMiraclesFromSemanticChanges.js +146 -0
- package/dist/core/utils/expandOpenApiRefsForSemanticDiff.d.ts +23 -0
- package/dist/core/utils/expandOpenApiRefsForSemanticDiff.d.ts.map +1 -0
- package/dist/core/utils/expandOpenApiRefsForSemanticDiff.js +163 -0
- package/dist/core/utils/getOpenApiSpec.d.ts +18 -0
- package/dist/core/utils/getOpenApiSpec.d.ts.map +1 -1
- package/dist/core/utils/getOpenApiSpec.js +35 -0
- package/dist/core/utils/loadDiffReport.d.ts +11 -30
- package/dist/core/utils/loadDiffReport.d.ts.map +1 -1
- package/dist/core/utils/loadDiffReport.js +69 -3
- package/dist/core/utils/loadSemanticOpenApiSpec.d.ts +15 -0
- package/dist/core/utils/loadSemanticOpenApiSpec.d.ts.map +1 -0
- package/dist/core/utils/loadSemanticOpenApiSpec.js +61 -0
- package/dist/core/utils/modelHelpers.d.ts +13 -5
- package/dist/core/utils/modelHelpers.d.ts.map +1 -1
- package/dist/core/utils/modelHelpers.js +28 -23
- package/dist/core/utils/prepareDtoModels.d.ts +5 -0
- package/dist/core/utils/prepareDtoModels.d.ts.map +1 -1
- package/dist/core/utils/prepareDtoModels.js +55 -12
- package/dist/core/utils/resolveClassesModeTypes.d.ts +8 -0
- package/dist/core/utils/resolveClassesModeTypes.d.ts.map +1 -0
- package/dist/core/utils/resolveClassesModeTypes.js +77 -0
- package/dist/core/utils/semanticChangesToDiffEntries.d.ts +37 -0
- package/dist/core/utils/semanticChangesToDiffEntries.d.ts.map +1 -0
- package/dist/core/utils/semanticChangesToDiffEntries.js +99 -0
- package/dist/core/utils/semanticPointerToJsonPath.d.ts +7 -0
- package/dist/core/utils/semanticPointerToJsonPath.d.ts.map +1 -0
- package/dist/core/utils/semanticPointerToJsonPath.js +67 -0
- package/dist/core/utils/serviceHelpers.d.ts +6 -7
- package/dist/core/utils/serviceHelpers.d.ts.map +1 -1
- package/dist/core/utils/serviceHelpers.js +8 -25
- package/dist/core/utils/writeClientServices.d.ts +14 -14
- package/dist/core/utils/writeClientServices.d.ts.map +1 -1
- package/dist/core/utils/writeClientServices.js +4 -8
- package/dist/templatesCompiled/client/exportModels.d.ts +17 -11
- package/dist/templatesCompiled/client/exportModels.d.ts.map +1 -1
- package/dist/templatesCompiled/client/exportModels.js +96 -49
- package/dist/templatesCompiled/client/exportService.d.ts +13 -10
- package/dist/templatesCompiled/client/exportService.d.ts.map +1 -1
- package/dist/templatesCompiled/client/exportService.js +95 -67
- package/package.json +1 -3
- package/dist/cli/analyzeDiff/buildLegacyReport.d.ts +0 -17
- package/dist/cli/analyzeDiff/buildLegacyReport.d.ts.map +0 -1
- package/dist/cli/analyzeDiff/buildLegacyReport.js +0 -54
- package/dist/cli/analyzeDiff/diffEngine.d.ts +0 -54
- package/dist/cli/analyzeDiff/diffEngine.d.ts.map +0 -1
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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;
|
|
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.
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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":"
|
|
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
|
|
6
|
-
|
|
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: [
|
|
14
|
+
enum: [DiffReport_model_1.UNIFIED_DIFF_REPORT_SCHEMA_VERSION],
|
|
13
15
|
required: true,
|
|
14
16
|
},
|
|
15
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
33
|
+
semantic: {
|
|
26
34
|
type: 'object',
|
|
27
35
|
additionalProperties: false,
|
|
28
36
|
required: true,
|
|
29
37
|
properties: {
|
|
30
|
-
|
|
31
|
-
type: '
|
|
32
|
-
|
|
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
|
-
|
|
36
|
-
type: '
|
|
37
|
-
|
|
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
|
-
|
|
41
|
-
type: '
|
|
42
|
-
|
|
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
|
-
|
|
114
|
+
changes: {
|
|
46
115
|
type: 'array',
|
|
47
|
-
minItems: 1,
|
|
48
116
|
required: true,
|
|
49
117
|
items: {
|
|
50
|
-
type: '
|
|
51
|
-
|
|
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
|
-
|
|
140
|
+
structural: {
|
|
57
141
|
type: 'object',
|
|
58
142
|
additionalProperties: false,
|
|
59
143
|
required: true,
|
|
60
144
|
properties: {
|
|
61
|
-
|
|
145
|
+
diff: {
|
|
62
146
|
type: 'object',
|
|
63
147
|
additionalProperties: false,
|
|
64
148
|
required: true,
|
|
65
149
|
properties: {
|
|
66
|
-
|
|
67
|
-
warnings: { type: '
|
|
68
|
-
info: { type: '
|
|
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
|
-
|
|
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
|
-
|
|
79
|
-
|
|
163
|
+
oldPath: { type: 'string', minLength: 1, required: true },
|
|
164
|
+
newPath: { type: 'string', minLength: 1, required: true },
|
|
165
|
+
type: {
|
|
80
166
|
type: 'string',
|
|
81
|
-
enum: ['
|
|
167
|
+
enum: ['RENAME', 'TYPE_COERCION'],
|
|
82
168
|
required: true,
|
|
83
169
|
},
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
*
|
|
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}`),
|