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
package/README.md
CHANGED
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
- Generated services accept a `RequestExecutor` in the constructor (`request` / `requestRaw`, interceptors, `customExecutorPath` / `createExecutorAdapter`)
|
|
35
35
|
- Optional output formatting via `prettierConfigPath` (explicit Prettier config file)
|
|
36
36
|
- Optional batch ESLint `--fix` after generation when both `tsconfigPath` and `eslintConfigPath` are set
|
|
37
|
+
- Supports unified `analyze-diff` report (`schemaVersion: 2.0.0`) with separate `semantic` (CI/governance) and `structural` (generation) sections
|
|
38
|
+
- Restores `generate --useHistory` compatibility with semantic diff reports (ghost operations/properties, coercion, rename miracles)
|
|
39
|
+
- Uses selective OpenAPI `$ref` expansion in analyze-diff for faster and safer comparison
|
|
40
|
+
- Automatic RENAME / TYPE_COERCION miracle detection from semantic property changes
|
|
37
41
|
|
|
38
42
|
## Install
|
|
39
43
|
|
package/README.rus.md
CHANGED
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
- Сгенерированные сервисы принимают `RequestExecutor` в конструкторе (`request` / `requestRaw`, interceptors, `customExecutorPath` / `createExecutorAdapter`)
|
|
35
35
|
- Опциональное форматирование вывода через `prettierConfigPath` (явный путь к конфигу Prettier)
|
|
36
36
|
- Опциональный пакетный ESLint `--fix` после генерации при указании `tsconfigPath` и `eslintConfigPath`
|
|
37
|
+
- Поддерживает унифицированный отчёт `analyze-diff` (`schemaVersion: 2.0.0`) с отдельными секциями `semantic` (CI/governance) и `structural` (генерация)
|
|
38
|
+
- Восстанавливает совместимость `generate --useHistory` с semantic diff-отчётами (ghost operations/properties, coercion, rename miracles)
|
|
39
|
+
- Использует селективное раскрытие OpenAPI `$ref` в analyze-diff для более быстрого и безопасного сравнения
|
|
40
|
+
- Автоматическое обнаружение RENAME / TYPE_COERCION miracles из semantic-изменений свойств
|
|
37
41
|
|
|
38
42
|
## Установка
|
|
39
43
|
|
|
@@ -111,12 +111,13 @@ async function runAnalyzeDiffCli(options) {
|
|
|
111
111
|
const report = JSON.parse((0, node_fs_1.readFileSync)(reportPath, 'utf8'));
|
|
112
112
|
const schemaValidation = (0, semanticDiffReportSchema_1.validateSemanticDiffReportSchema)(report);
|
|
113
113
|
node_assert_1.default.strictEqual(schemaValidation.valid, true, schemaValidation.errors.join('\n'));
|
|
114
|
-
node_assert_1.default.strictEqual(report.schemaVersion, '
|
|
115
|
-
node_assert_1.default.strictEqual(report.summary.breaking, 0);
|
|
116
|
-
node_assert_1.default.ok(report.summary.nonBreaking > 0);
|
|
117
|
-
node_assert_1.default.strictEqual(report.recommendation.semver, 'minor');
|
|
118
|
-
node_assert_1.default.ok(report.recommendation.reasons.includes('HAS_BACKWARD_COMPATIBLE_CHANGES'));
|
|
119
|
-
node_assert_1.default.strictEqual(report.governance.summary.errors, 0);
|
|
114
|
+
node_assert_1.default.strictEqual(report.schemaVersion, '2.0.0');
|
|
115
|
+
node_assert_1.default.strictEqual(report.semantic.summary.breaking, 0);
|
|
116
|
+
node_assert_1.default.ok(report.semantic.summary.nonBreaking > 0);
|
|
117
|
+
node_assert_1.default.strictEqual(report.semantic.recommendation.semver, 'minor');
|
|
118
|
+
node_assert_1.default.ok(report.semantic.recommendation.reasons.includes('HAS_BACKWARD_COMPATIBLE_CHANGES'));
|
|
119
|
+
node_assert_1.default.strictEqual(report.semantic.governance.summary.errors, 0);
|
|
120
|
+
node_assert_1.default.strictEqual(report.structural.diff.all.length, report.semantic.changes.length);
|
|
120
121
|
const ciSummary = (0, ciSummary_1.formatCiMarkdownSummary)(report, reportPath);
|
|
121
122
|
node_assert_1.default.ok(ciSummary.includes('### OpenAPI Semantic Diff'));
|
|
122
123
|
node_assert_1.default.ok(ciSummary.includes('HAS_BACKWARD_COMPATIBLE_CHANGES'));
|
|
@@ -154,12 +155,12 @@ async function runAnalyzeDiffCli(options) {
|
|
|
154
155
|
const report = JSON.parse((0, node_fs_1.readFileSync)(reportPath, 'utf8'));
|
|
155
156
|
const schemaValidation = (0, semanticDiffReportSchema_1.validateSemanticDiffReportSchema)(report);
|
|
156
157
|
node_assert_1.default.strictEqual(schemaValidation.valid, true, schemaValidation.errors.join('\n'));
|
|
157
|
-
node_assert_1.default.strictEqual(report.schemaVersion, '
|
|
158
|
-
node_assert_1.default.ok(report.summary.breaking > 0);
|
|
159
|
-
node_assert_1.default.ok(report.changes.some(change => change.severity === 'breaking'));
|
|
160
|
-
node_assert_1.default.strictEqual(report.recommendation.semver, 'major');
|
|
161
|
-
node_assert_1.default.ok(report.recommendation.reasons.includes('HAS_BREAKING_CHANGES'));
|
|
162
|
-
node_assert_1.default.ok(report.governance.violations.some(violation => violation.ruleId === 'NO_BREAKING_WITHOUT_FLAG'));
|
|
158
|
+
node_assert_1.default.strictEqual(report.schemaVersion, '2.0.0');
|
|
159
|
+
node_assert_1.default.ok(report.semantic.summary.breaking > 0);
|
|
160
|
+
node_assert_1.default.ok(report.semantic.changes.some(change => change.severity === 'breaking'));
|
|
161
|
+
node_assert_1.default.strictEqual(report.semantic.recommendation.semver, 'major');
|
|
162
|
+
node_assert_1.default.ok(report.semantic.recommendation.reasons.includes('HAS_BREAKING_CHANGES'));
|
|
163
|
+
node_assert_1.default.ok(report.semantic.governance.violations.some(violation => violation.ruleId === 'NO_BREAKING_WITHOUT_FLAG'));
|
|
163
164
|
const ciSummary = (0, ciSummary_1.formatCiMarkdownSummary)(report, reportPath);
|
|
164
165
|
node_assert_1.default.ok(ciSummary.includes('### OpenAPI Semantic Diff'));
|
|
165
166
|
node_assert_1.default.ok(ciSummary.includes('HAS_BREAKING_CHANGES'));
|
|
@@ -199,9 +200,9 @@ async function runAnalyzeDiffCli(options) {
|
|
|
199
200
|
const report = JSON.parse((0, node_fs_1.readFileSync)(reportPath, 'utf8'));
|
|
200
201
|
const schemaValidation = (0, semanticDiffReportSchema_1.validateSemanticDiffReportSchema)(report);
|
|
201
202
|
node_assert_1.default.strictEqual(schemaValidation.valid, true, schemaValidation.errors.join('\n'));
|
|
202
|
-
node_assert_1.default.strictEqual(report.schemaVersion, '
|
|
203
|
-
node_assert_1.default.ok(report.summary.breaking > 0);
|
|
204
|
-
node_assert_1.default.ok(!report.governance.violations.some(violation => violation.ruleId === 'NO_BREAKING_WITHOUT_FLAG'));
|
|
203
|
+
node_assert_1.default.strictEqual(report.schemaVersion, '2.0.0');
|
|
204
|
+
node_assert_1.default.ok(report.semantic.summary.breaking > 0);
|
|
205
|
+
node_assert_1.default.ok(!report.semantic.governance.violations.some(violation => violation.ruleId === 'NO_BREAKING_WITHOUT_FLAG'));
|
|
205
206
|
node_assert_1.default.ok((0, ciSummary_1.formatCiMarkdownSummary)(report, reportPath).includes('### OpenAPI Semantic Diff'));
|
|
206
207
|
});
|
|
207
208
|
(0, node_test_1.test)('returns exit code 0 for breaking diff in ci mode when governance config disables no-breaking rule', async (t) => {
|
|
@@ -247,9 +248,9 @@ async function runAnalyzeDiffCli(options) {
|
|
|
247
248
|
const report = JSON.parse((0, node_fs_1.readFileSync)(reportPath, 'utf8'));
|
|
248
249
|
const schemaValidation = (0, semanticDiffReportSchema_1.validateSemanticDiffReportSchema)(report);
|
|
249
250
|
node_assert_1.default.strictEqual(schemaValidation.valid, true, schemaValidation.errors.join('\n'));
|
|
250
|
-
node_assert_1.default.strictEqual(report.schemaVersion, '
|
|
251
|
-
node_assert_1.default.ok(report.summary.breaking > 0);
|
|
252
|
-
node_assert_1.default.ok(!report.governance.violations.some(violation => violation.ruleId === 'NO_BREAKING_WITHOUT_FLAG'));
|
|
251
|
+
node_assert_1.default.strictEqual(report.schemaVersion, '2.0.0');
|
|
252
|
+
node_assert_1.default.ok(report.semantic.summary.breaking > 0);
|
|
253
|
+
node_assert_1.default.ok(!report.semantic.governance.violations.some(violation => violation.ruleId === 'NO_BREAKING_WITHOUT_FLAG'));
|
|
253
254
|
node_assert_1.default.ok((0, ciSummary_1.formatCiMarkdownSummary)(report, reportPath).includes('### OpenAPI Semantic Diff'));
|
|
254
255
|
});
|
|
255
256
|
(0, node_test_1.test)('uses --compare-with over --git when both flags are provided', async (t) => {
|
|
@@ -293,8 +294,8 @@ async function runAnalyzeDiffCli(options) {
|
|
|
293
294
|
node_assert_1.default.strictEqual(exitCode, 0);
|
|
294
295
|
node_assert_1.default.strictEqual(result.success, true);
|
|
295
296
|
const report = JSON.parse((0, node_fs_1.readFileSync)(reportPath, 'utf8'));
|
|
296
|
-
node_assert_1.default.strictEqual(report.summary.breaking, 0);
|
|
297
|
-
node_assert_1.default.strictEqual(report.recommendation.semver, 'patch');
|
|
297
|
+
node_assert_1.default.strictEqual(report.semantic.summary.breaking, 0);
|
|
298
|
+
node_assert_1.default.strictEqual(report.semantic.recommendation.semver, 'patch');
|
|
298
299
|
node_assert_1.default.ok(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.COMPARE_WITH_OVERRIDES_GIT('HEAD~9999').includes('Ignoring git ref'));
|
|
299
300
|
});
|
|
300
301
|
(0, node_test_1.test)('filters semantic changes with analyze.ignore and recalculates summary', async (t) => {
|
|
@@ -355,10 +356,10 @@ async function runAnalyzeDiffCli(options) {
|
|
|
355
356
|
node_assert_1.default.strictEqual(exitCode, 0);
|
|
356
357
|
node_assert_1.default.strictEqual(result.ignored, 1);
|
|
357
358
|
const report = JSON.parse((0, node_fs_1.readFileSync)(reportPath, 'utf8'));
|
|
358
|
-
node_assert_1.default.strictEqual(report.summary.breaking, 0);
|
|
359
|
-
node_assert_1.default.strictEqual(report.summary.nonBreaking, 0);
|
|
360
|
-
node_assert_1.default.strictEqual(report.summary.informational, 0);
|
|
361
|
-
node_assert_1.default.strictEqual(report.recommendation.semver, 'patch');
|
|
359
|
+
node_assert_1.default.strictEqual(report.semantic.summary.breaking, 0);
|
|
360
|
+
node_assert_1.default.strictEqual(report.semantic.summary.nonBreaking, 0);
|
|
361
|
+
node_assert_1.default.strictEqual(report.semantic.summary.informational, 0);
|
|
362
|
+
node_assert_1.default.strictEqual(report.semantic.recommendation.semver, 'patch');
|
|
362
363
|
node_assert_1.default.ok(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.IGNORED_CHANGES(1).includes('IGNORED: 1 semantic change'));
|
|
363
364
|
});
|
|
364
365
|
(0, node_test_1.test)('fails when --input is missing', async () => {
|
|
@@ -371,4 +372,10 @@ async function runAnalyzeDiffCli(options) {
|
|
|
371
372
|
node_assert_1.default.strictEqual((0, analyzeDiff_1.toAnalyzeDiffExitCode)(result), 1);
|
|
372
373
|
node_assert_1.default.ok(result.error?.includes('"--input" is required for analyze-diff command'));
|
|
373
374
|
});
|
|
375
|
+
(0, node_test_1.test)('uses semantic ref expansion instead of full dereference in the analyze hot path', () => {
|
|
376
|
+
const source = (0, node_fs_1.readFileSync)(node_path_1.default.join(__dirname, '..', 'analyzeDiff.ts'), 'utf8');
|
|
377
|
+
node_assert_1.default.ok(source.includes('loadSemanticOpenApiSpec'));
|
|
378
|
+
node_assert_1.default.ok(!source.includes('dereferenceOpenApiSpec'));
|
|
379
|
+
node_assert_1.default.ok(!source.includes('dereferenceOpenApiObject'));
|
|
380
|
+
});
|
|
374
381
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzeDiffLomMiracles.test.d.ts","sourceRoot":"","sources":["../../../../src/cli/analyzeDiff/__tests__/analyzeDiffLomMiracles.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const node_test_1 = require("node:test");
|
|
10
|
+
const silenceLoggers_1 = require("../../../test/helpers/silenceLoggers");
|
|
11
|
+
const analyzeDiff_1 = require("../analyzeDiff");
|
|
12
|
+
const generatedRoot = node_path_1.default.join(__dirname, 'generated');
|
|
13
|
+
const createTempDir = (t, prefix) => {
|
|
14
|
+
node_fs_1.default.mkdirSync(generatedRoot, { recursive: true });
|
|
15
|
+
const tempDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(generatedRoot, prefix));
|
|
16
|
+
t.after(() => {
|
|
17
|
+
node_fs_1.default.rmSync(tempDir, { recursive: true, force: true });
|
|
18
|
+
});
|
|
19
|
+
return tempDir;
|
|
20
|
+
};
|
|
21
|
+
(0, node_test_1.describe)('@unit: analyzeDiff lom miracles', () => {
|
|
22
|
+
let restoreAppLogger;
|
|
23
|
+
(0, node_test_1.beforeEach)(() => {
|
|
24
|
+
restoreAppLogger = (0, silenceLoggers_1.installSilenceAppLogger)();
|
|
25
|
+
});
|
|
26
|
+
(0, node_test_1.afterEach)(() => {
|
|
27
|
+
restoreAppLogger?.();
|
|
28
|
+
restoreAppLogger = undefined;
|
|
29
|
+
});
|
|
30
|
+
(0, node_test_1.test)('builds changes and miracles for lom v1 vs v2 specs', async (t) => {
|
|
31
|
+
const tmpDir = createTempDir(t, 'lom-diff-');
|
|
32
|
+
const reportPath = node_path_1.default.join(tmpDir, 'report.json');
|
|
33
|
+
const specRoot = node_path_1.default.join(__dirname, '../../../../test/spec/lom');
|
|
34
|
+
const result = await (0, analyzeDiff_1.analyzeDiff)({
|
|
35
|
+
input: node_path_1.default.join(specRoot, 'lom_api.v2.yaml'),
|
|
36
|
+
compareWith: node_path_1.default.join(specRoot, 'lom_api.v1.yaml'),
|
|
37
|
+
outputReport: reportPath,
|
|
38
|
+
});
|
|
39
|
+
node_assert_1.default.ok(result.success, result.error);
|
|
40
|
+
const report = JSON.parse(node_fs_1.default.readFileSync(reportPath, 'utf-8'));
|
|
41
|
+
node_assert_1.default.ok(report.semantic.changes.length > 0, 'expected semantic changes');
|
|
42
|
+
node_assert_1.default.ok(report.structural.miracles.length > 0, 'expected miracles in report');
|
|
43
|
+
node_assert_1.default.ok(report.structural.miracles.some(miracle => miracle.type === 'RENAME'));
|
|
44
|
+
node_assert_1.default.ok(report.structural.miracles.some(miracle => miracle.type === 'TYPE_COERCION'));
|
|
45
|
+
node_assert_1.default.ok(report.semantic.changes.some(change => change.type === 'model.property.type.changed'));
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -75,12 +75,13 @@ const createTempDir = (t, prefix) => {
|
|
|
75
75
|
node_assert_1.default.ok(result.success, `analyzeDiff failed: ${result.error ?? 'unknown'}`);
|
|
76
76
|
const reportRaw = node_fs_1.default.readFileSync(reportPath, 'utf-8');
|
|
77
77
|
const report = JSON.parse(reportRaw);
|
|
78
|
-
const removed = report.changes.find(change => change.type === 'model.property.removed' && change.path === '#/components/schemas/User/properties/first_name');
|
|
79
|
-
const added = report.changes.find(change => change.type === 'model.property.added' && change.path === '#/components/schemas/User/properties/firstName');
|
|
78
|
+
const removed = report.semantic.changes.find(change => change.type === 'model.property.removed' && change.path === '#/components/schemas/User/properties/first_name');
|
|
79
|
+
const added = report.semantic.changes.find(change => change.type === 'model.property.added' && change.path === '#/components/schemas/User/properties/firstName');
|
|
80
80
|
node_assert_1.default.ok(removed, 'Expected semantic removal entry for previous property');
|
|
81
81
|
node_assert_1.default.ok(added, 'Expected semantic addition entry for renamed property');
|
|
82
82
|
node_assert_1.default.strictEqual(removed?.severity, 'breaking');
|
|
83
83
|
node_assert_1.default.strictEqual(added?.severity, 'non-breaking');
|
|
84
|
+
node_assert_1.default.ok(report.structural.miracles.some(miracle => miracle.type === 'RENAME'));
|
|
84
85
|
});
|
|
85
86
|
(0, node_test_1.test)('invalid regex in config does not crash and valid rules still apply', async (t) => {
|
|
86
87
|
const tmpDir = createTempDir(t, 'openapi-diff-invalidregex-');
|
|
@@ -141,11 +142,11 @@ const createTempDir = (t, prefix) => {
|
|
|
141
142
|
node_assert_1.default.ok(result.success, `analyzeDiff failed: ${result.error ?? 'unknown'}`);
|
|
142
143
|
const reportRaw = node_fs_1.default.readFileSync(reportPath, 'utf-8');
|
|
143
144
|
const report = JSON.parse(reportRaw);
|
|
144
|
-
const filteredTypeChange = report.changes.find(change => change.type === 'model.property.type.changed' && change.path === '#/components/schemas/User/properties/age');
|
|
145
|
+
const filteredTypeChange = report.semantic.changes.find(change => change.type === 'model.property.type.changed' && change.path === '#/components/schemas/User/properties/age');
|
|
145
146
|
node_assert_1.default.ok(!filteredTypeChange, 'Expected matching semantic change to be filtered by valid rule while invalid regex is ignored');
|
|
146
|
-
node_assert_1.default.strictEqual(report.summary.breaking, 0);
|
|
147
|
-
node_assert_1.default.strictEqual(report.summary.nonBreaking, 0);
|
|
148
|
-
node_assert_1.default.strictEqual(report.summary.informational, 0);
|
|
149
|
-
node_assert_1.default.strictEqual(report.recommendation.semver, 'patch');
|
|
147
|
+
node_assert_1.default.strictEqual(report.semantic.summary.breaking, 0);
|
|
148
|
+
node_assert_1.default.strictEqual(report.semantic.summary.nonBreaking, 0);
|
|
149
|
+
node_assert_1.default.strictEqual(report.semantic.summary.informational, 0);
|
|
150
|
+
node_assert_1.default.strictEqual(report.semantic.recommendation.semver, 'patch');
|
|
150
151
|
});
|
|
151
152
|
});
|
|
@@ -75,11 +75,12 @@ const createTempDir = (t, prefix) => {
|
|
|
75
75
|
node_assert_1.default.ok(result.success, `analyzeDiff failed: ${result.error ?? 'unknown error'}`);
|
|
76
76
|
const reportRaw = node_fs_1.default.readFileSync(reportPath, 'utf-8');
|
|
77
77
|
const report = JSON.parse(reportRaw);
|
|
78
|
-
const typeChange = report.changes.find(change => change.type === 'model.property.type.changed');
|
|
78
|
+
const typeChange = report.semantic.changes.find(change => change.type === 'model.property.type.changed');
|
|
79
79
|
node_assert_1.default.ok(typeChange, 'Expected semantic type-change entry');
|
|
80
80
|
node_assert_1.default.strictEqual(typeChange?.path, '#/components/schemas/User/properties/age');
|
|
81
81
|
node_assert_1.default.strictEqual(typeChange?.severity, 'breaking');
|
|
82
|
-
node_assert_1.default.ok(report.summary.breaking > 0);
|
|
82
|
+
node_assert_1.default.ok(report.semantic.summary.breaking > 0);
|
|
83
|
+
node_assert_1.default.ok(report.structural.miracles.some(miracle => miracle.type === 'TYPE_COERCION'));
|
|
83
84
|
});
|
|
84
85
|
(0, node_test_1.test)('filters semantic type-change entry when rule matches path', async (t) => {
|
|
85
86
|
const tmpDir = createTempDir(t, 'openapi-diff-test-');
|
|
@@ -136,11 +137,11 @@ const createTempDir = (t, prefix) => {
|
|
|
136
137
|
node_assert_1.default.ok(result.success, `analyzeDiff failed: ${result.error ?? 'unknown error'}`);
|
|
137
138
|
const reportRaw = node_fs_1.default.readFileSync(reportPath, 'utf-8');
|
|
138
139
|
const report = JSON.parse(reportRaw);
|
|
139
|
-
const filteredTypeChange = report.changes.find(change => change.type === 'model.property.type.changed' && change.path === '#/components/schemas/User/properties/age');
|
|
140
|
+
const filteredTypeChange = report.semantic.changes.find(change => change.type === 'model.property.type.changed' && change.path === '#/components/schemas/User/properties/age');
|
|
140
141
|
node_assert_1.default.ok(!filteredTypeChange, 'Expected semantic type-change to be filtered by analyze.ignore');
|
|
141
|
-
node_assert_1.default.strictEqual(report.summary.breaking, 0);
|
|
142
|
-
node_assert_1.default.strictEqual(report.summary.nonBreaking, 0);
|
|
143
|
-
node_assert_1.default.strictEqual(report.summary.informational, 0);
|
|
144
|
-
node_assert_1.default.strictEqual(report.recommendation.semver, 'patch');
|
|
142
|
+
node_assert_1.default.strictEqual(report.semantic.summary.breaking, 0);
|
|
143
|
+
node_assert_1.default.strictEqual(report.semantic.summary.nonBreaking, 0);
|
|
144
|
+
node_assert_1.default.strictEqual(report.semantic.summary.informational, 0);
|
|
145
|
+
node_assert_1.default.strictEqual(report.semantic.recommendation.semver, 'patch');
|
|
145
146
|
});
|
|
146
147
|
});
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { OptionValues } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Результат выполнения команды analyze-diff.
|
|
4
|
+
* @property success признак успешного завершения
|
|
5
|
+
* @property [skipped] анализ пропущен из-за отсутствия базовой спецификации
|
|
6
|
+
* @property [reportPath] абсолютный путь к сохранённому отчёту
|
|
7
|
+
* @property [ignored] количество проигнорированных изменений
|
|
8
|
+
* @property [error] текст ошибки при неуспешном завершении
|
|
9
|
+
*/
|
|
2
10
|
export type AnalyzeDiffResult = {
|
|
3
11
|
success: boolean;
|
|
4
12
|
skipped?: boolean;
|
|
@@ -7,11 +15,15 @@ export type AnalyzeDiffResult = {
|
|
|
7
15
|
error?: string;
|
|
8
16
|
};
|
|
9
17
|
/**
|
|
10
|
-
*
|
|
18
|
+
* Преобразует результат analyze-diff в код выхода процесса. Не вызывает `process.exit`.
|
|
19
|
+
* @param result результат выполнения analyze-diff
|
|
20
|
+
* @returns код выхода: 0 при успехе, 1 при ошибке
|
|
11
21
|
*/
|
|
12
22
|
export declare function toAnalyzeDiffExitCode(result: AnalyzeDiffResult): number;
|
|
13
23
|
/**
|
|
14
|
-
*
|
|
24
|
+
* Выполняет семантическое сравнение двух OpenAPI-спецификаций и записывает JSON-отчёт.
|
|
25
|
+
* @param options опции CLI команды analyze-diff
|
|
26
|
+
* @returns результат выполнения с путём к отчёту или описанием ошибки
|
|
15
27
|
*/
|
|
16
28
|
export declare function analyzeDiff(options: OptionValues): Promise<AnalyzeDiffResult>;
|
|
17
29
|
//# sourceMappingURL=analyzeDiff.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzeDiff.d.ts","sourceRoot":"","sources":["../../../src/cli/analyzeDiff/analyzeDiff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"analyzeDiff.d.ts","sourceRoot":"","sources":["../../../src/cli/analyzeDiff/analyzeDiff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAuBzC;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAEvE;AAqBD;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuGnF"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.toAnalyzeDiffExitCode = toAnalyzeDiffExitCode;
|
|
4
7
|
exports.analyzeDiff = analyzeDiff;
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
5
9
|
const Consts_1 = require("../../common/Consts");
|
|
6
10
|
const LoggerMessages_1 = require("../../common/LoggerMessages");
|
|
7
11
|
const validateZodOptions_1 = require("../../common/Validation/validateZodOptions");
|
|
@@ -10,7 +14,10 @@ const loadGovernanceConfig_1 = require("../../core/governance/loadGovernanceConf
|
|
|
10
14
|
const applySemanticDiffPluginHooks_1 = require("../../core/plugins/applySemanticDiffPluginHooks");
|
|
11
15
|
const loadGeneratorPlugins_1 = require("../../core/plugins/loadGeneratorPlugins");
|
|
12
16
|
const analyzeOpenApiDiff_1 = require("../../core/semanticDiff/analyzeOpenApiDiff");
|
|
13
|
-
const
|
|
17
|
+
const DiffReport_model_1 = require("../../core/types/DiffReport.model");
|
|
18
|
+
const adapters_1 = require("../../core/utils/adapters");
|
|
19
|
+
const buildMiraclesFromSemanticChanges_1 = require("../../core/utils/buildMiraclesFromSemanticChanges");
|
|
20
|
+
const loadSemanticOpenApiSpec_1 = require("../../core/utils/loadSemanticOpenApiSpec");
|
|
14
21
|
const schemas_1 = require("../schemas");
|
|
15
22
|
const ciSummary_1 = require("./ciSummary");
|
|
16
23
|
const ignoreRules_1 = require("./ignoreRules");
|
|
@@ -19,13 +26,33 @@ const pluginPaths_1 = require("./pluginPaths");
|
|
|
19
26
|
const semanticDiffContext_1 = require("./semanticDiffContext");
|
|
20
27
|
const specParser_1 = require("./specParser");
|
|
21
28
|
/**
|
|
22
|
-
*
|
|
29
|
+
* Преобразует результат analyze-diff в код выхода процесса. Не вызывает `process.exit`.
|
|
30
|
+
* @param result результат выполнения analyze-diff
|
|
31
|
+
* @returns код выхода: 0 при успехе, 1 при ошибке
|
|
23
32
|
*/
|
|
24
33
|
function toAnalyzeDiffExitCode(result) {
|
|
25
34
|
return result.success ? 0 : 1;
|
|
26
35
|
}
|
|
36
|
+
function createSpecHash(spec) {
|
|
37
|
+
const seen = new WeakSet();
|
|
38
|
+
const serializedSpec = JSON.stringify(spec, (_key, value) => {
|
|
39
|
+
if (value && typeof value === 'object') {
|
|
40
|
+
if (seen.has(value)) {
|
|
41
|
+
return '[Circular]';
|
|
42
|
+
}
|
|
43
|
+
seen.add(value);
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
});
|
|
47
|
+
return crypto_1.default
|
|
48
|
+
.createHash('sha256')
|
|
49
|
+
.update(serializedSpec ?? '')
|
|
50
|
+
.digest('hex');
|
|
51
|
+
}
|
|
27
52
|
/**
|
|
28
|
-
*
|
|
53
|
+
* Выполняет семантическое сравнение двух OpenAPI-спецификаций и записывает JSON-отчёт.
|
|
54
|
+
* @param options опции CLI команды analyze-diff
|
|
55
|
+
* @returns результат выполнения с путём к отчёту или описанием ошибки
|
|
29
56
|
*/
|
|
30
57
|
async function analyzeDiff(options) {
|
|
31
58
|
const validationResult = (0, validateZodOptions_1.validateZodOptions)(schemas_1.analyzeDiffOptionsSchema, options);
|
|
@@ -46,11 +73,9 @@ async function analyzeDiff(options) {
|
|
|
46
73
|
}
|
|
47
74
|
const baseSourceLabel = oldSpecInput ? `compare-with:${oldSpecInput}` : `git:${gitRef}`;
|
|
48
75
|
Consts_1.APP_LOGGER.info(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.STARTED(newSpecInput, baseSourceLabel));
|
|
49
|
-
|
|
50
|
-
const newSpec = await (0,
|
|
51
|
-
const oldSpec = oldSpecInput
|
|
52
|
-
? await (0, getOpenApiSpec_1.getOpenApiSpec)((0, semanticDiffContext_1.createSemanticDiffContext)(oldSpecInput), oldSpecInput)
|
|
53
|
-
: (await (0, specParser_1.readSpecFromGit)(gitRef, newSpecInput));
|
|
76
|
+
(0, semanticDiffContext_1.createSemanticDiffContext)(newSpecInput);
|
|
77
|
+
const newSpec = await (0, loadSemanticOpenApiSpec_1.loadSemanticOpenApiSpec)(newSpecInput);
|
|
78
|
+
const oldSpec = oldSpecInput ? await (0, loadSemanticOpenApiSpec_1.loadSemanticOpenApiSpec)(oldSpecInput) : await (0, loadSemanticOpenApiSpec_1.loadSemanticOpenApiObject)(await (0, specParser_1.readSpecFromGit)(gitRef, newSpecInput), newSpecInput);
|
|
54
79
|
if (oldSpecInput && validatedOptions.git) {
|
|
55
80
|
Consts_1.APP_LOGGER.info(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.COMPARE_WITH_OVERRIDES_GIT(validatedOptions.git));
|
|
56
81
|
}
|
|
@@ -72,7 +97,7 @@ async function analyzeDiff(options) {
|
|
|
72
97
|
},
|
|
73
98
|
});
|
|
74
99
|
const { report: reportAfterIgnore, ignored } = (0, ignoreSemanticChanges_1.filterSemanticChangesByIgnoreRules)(pluginHooksResult.report, ignoreRules);
|
|
75
|
-
const
|
|
100
|
+
const semanticReport = {
|
|
76
101
|
...reportAfterIgnore,
|
|
77
102
|
governance: (0, evaluateGovernanceRules_1.evaluateGovernanceRules)({
|
|
78
103
|
openApi: newSpec,
|
|
@@ -80,19 +105,37 @@ async function analyzeDiff(options) {
|
|
|
80
105
|
allowBreaking: validatedOptions.allowBreaking ?? false,
|
|
81
106
|
governanceConfig: governancePolicy,
|
|
82
107
|
}),
|
|
108
|
+
miracles: (0, buildMiraclesFromSemanticChanges_1.buildMiraclesFromSemanticChanges)(reportAfterIgnore.changes),
|
|
109
|
+
};
|
|
110
|
+
const report = {
|
|
111
|
+
schemaVersion: DiffReport_model_1.UNIFIED_DIFF_REPORT_SCHEMA_VERSION,
|
|
112
|
+
timestamp: new Date().toISOString(),
|
|
113
|
+
metadata: {
|
|
114
|
+
base: baseSourceLabel,
|
|
115
|
+
target: newSpecInput,
|
|
116
|
+
baseHash: createSpecHash(oldSpec),
|
|
117
|
+
targetHash: createSpecHash(newSpec),
|
|
118
|
+
},
|
|
119
|
+
semantic: {
|
|
120
|
+
changes: semanticReport.changes,
|
|
121
|
+
governance: semanticReport.governance,
|
|
122
|
+
recommendation: semanticReport.recommendation,
|
|
123
|
+
summary: semanticReport.summary,
|
|
124
|
+
},
|
|
125
|
+
structural: (0, adapters_1.adaptSemanticToStructural)(semanticReport, ignored),
|
|
83
126
|
};
|
|
84
127
|
const reportPath = await (0, analyzeOpenApiDiff_1.writeSemanticDiffReport)(report, pluginHooksResult.reportPath);
|
|
85
128
|
Consts_1.APP_LOGGER.info(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.REPORT_CREATED(reportPath));
|
|
86
|
-
Consts_1.APP_LOGGER.info(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.SUMMARY(
|
|
87
|
-
Consts_1.APP_LOGGER.info(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.RECOMMENDATION(
|
|
88
|
-
Consts_1.APP_LOGGER.info(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.GOVERNANCE(
|
|
129
|
+
Consts_1.APP_LOGGER.info(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.SUMMARY(semanticReport, reportPath));
|
|
130
|
+
Consts_1.APP_LOGGER.info(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.RECOMMENDATION(semanticReport));
|
|
131
|
+
Consts_1.APP_LOGGER.info(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.GOVERNANCE(semanticReport));
|
|
89
132
|
if (ignored > 0) {
|
|
90
133
|
Consts_1.APP_LOGGER.info(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.IGNORED_CHANGES(ignored));
|
|
91
134
|
}
|
|
92
135
|
if (validatedOptions.ci) {
|
|
93
136
|
Consts_1.APP_LOGGER.info(LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.CI_MARKDOWN_SUMMARY((0, ciSummary_1.formatCiMarkdownSummary)(report, reportPath)));
|
|
94
137
|
}
|
|
95
|
-
if (validatedOptions.ci &&
|
|
138
|
+
if (validatedOptions.ci && semanticReport.governance.summary.errors > 0) {
|
|
96
139
|
return { success: false, reportPath, error: LoggerMessages_1.LOGGER_MESSAGES.ANALYZE_DIFF.CI_FAILURE };
|
|
97
140
|
}
|
|
98
141
|
return { success: true, reportPath, ignored };
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { UnifiedDiffReport } from '../../core/types/DiffReport.model';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Формирует markdown-сводку семантического diff для CI-логов.
|
|
4
|
+
* @param report унифицированный diff-отчёт
|
|
5
|
+
* @param reportPath путь к сохранённому отчёту
|
|
6
|
+
* @returns markdown-текст для вывода в CI
|
|
4
7
|
*/
|
|
5
|
-
export declare function formatCiMarkdownSummary(report:
|
|
8
|
+
export declare function formatCiMarkdownSummary(report: UnifiedDiffReport, reportPath: string): string;
|
|
6
9
|
//# sourceMappingURL=ciSummary.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ciSummary.d.ts","sourceRoot":"","sources":["../../../src/cli/analyzeDiff/ciSummary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ciSummary.d.ts","sourceRoot":"","sources":["../../../src/cli/analyzeDiff/ciSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAE3E;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAe7F"}
|
|
@@ -2,19 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatCiMarkdownSummary = formatCiMarkdownSummary;
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Формирует markdown-сводку семантического diff для CI-логов.
|
|
6
|
+
* @param report унифицированный diff-отчёт
|
|
7
|
+
* @param reportPath путь к сохранённому отчёту
|
|
8
|
+
* @returns markdown-текст для вывода в CI
|
|
6
9
|
*/
|
|
7
10
|
function formatCiMarkdownSummary(report, reportPath) {
|
|
8
|
-
const
|
|
11
|
+
const semantic = report.semantic;
|
|
12
|
+
const reasons = semantic.recommendation.reasons.map(reason => `- \`${reason}\``).join('\n');
|
|
9
13
|
return [
|
|
10
14
|
'### OpenAPI Semantic Diff',
|
|
11
15
|
`- Report: \`${reportPath}\``,
|
|
12
16
|
`- Schema Version: \`${report.schemaVersion}\``,
|
|
13
|
-
`- Recommendation: \`${
|
|
14
|
-
`- Reason: ${
|
|
17
|
+
`- Recommendation: \`${semantic.recommendation.semver}\` (confidence: \`${semantic.recommendation.confidence}\`)`,
|
|
18
|
+
`- Reason: ${semantic.recommendation.reason}`,
|
|
15
19
|
'- Reason Codes:',
|
|
16
20
|
reasons,
|
|
17
|
-
`- Summary: breaking=\`${
|
|
18
|
-
`- Governance: errors=\`${
|
|
21
|
+
`- Summary: breaking=\`${semantic.summary.breaking}\`, nonBreaking=\`${semantic.summary.nonBreaking}\`, informational=\`${semantic.summary.informational}\``,
|
|
22
|
+
`- Governance: errors=\`${semantic.governance.summary.errors}\`, warnings=\`${semantic.governance.summary.warnings}\`, info=\`${semantic.governance.summary.info}\``,
|
|
19
23
|
].join('\n');
|
|
20
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/cli/analyzeDiff/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,IAAI,
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/cli/analyzeDiff/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.writeReportToFile =
|
|
4
|
-
var buildLegacyReport_1 = require("./buildLegacyReport");
|
|
5
|
-
Object.defineProperty(exports, "buildReport", { enumerable: true, get: function () { return buildLegacyReport_1.buildLegacyReport; } });
|
|
3
|
+
exports.writeReportToFile = void 0;
|
|
6
4
|
var writeLegacyReport_1 = require("./writeLegacyReport");
|
|
7
5
|
Object.defineProperty(exports, "writeReportToFile", { enumerable: true, get: function () { return writeLegacyReport_1.writeLegacyReport; } });
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { DiffReport } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* Сохраняет legacy report на диск и логирует summary.
|
|
4
|
+
* @param report legacy diff-отчёт
|
|
5
|
+
* @param [reportPath] путь к файлу отчёта
|
|
4
6
|
*/
|
|
5
7
|
export declare function writeLegacyReport(report: DiffReport, reportPath?: string): void;
|
|
6
8
|
//# sourceMappingURL=writeLegacyReport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeLegacyReport.d.ts","sourceRoot":"","sources":["../../../src/cli/analyzeDiff/writeLegacyReport.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC
|
|
1
|
+
{"version":3,"file":"writeLegacyReport.d.ts","sourceRoot":"","sources":["../../../src/cli/analyzeDiff/writeLegacyReport.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,GAAE,MAAyC,GAAG,IAAI,CASjH"}
|
|
@@ -10,6 +10,8 @@ const Consts_1 = require("../../common/Consts");
|
|
|
10
10
|
const logLegacyReport_1 = require("./logLegacyReport");
|
|
11
11
|
/**
|
|
12
12
|
* Сохраняет legacy report на диск и логирует summary.
|
|
13
|
+
* @param report legacy diff-отчёт
|
|
14
|
+
* @param [reportPath] путь к файлу отчёта
|
|
13
15
|
*/
|
|
14
16
|
function writeLegacyReport(report, reportPath = Consts_1.DEFAULT_ANALYZE_DIFF_REPORT_PATH) {
|
|
15
17
|
const reportDir = path_1.default.dirname(reportPath);
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { SourceFile } from 'ts-morph';
|
|
2
2
|
import type { Contract } from '../types';
|
|
3
|
+
/** Сканер экспортов сгенерированного API-файла для построения контракта. */
|
|
3
4
|
export declare class Scanner {
|
|
4
5
|
private generatedFile;
|
|
6
|
+
/**
|
|
7
|
+
* @param generatedFile сгенерированный исходный файл API
|
|
8
|
+
*/
|
|
5
9
|
constructor(generatedFile: SourceFile);
|
|
10
|
+
/**
|
|
11
|
+
* Сканирует экспорты файла и собирает контракт сервисов, моделей и схем.
|
|
12
|
+
* @returns контракт сгенерированного API
|
|
13
|
+
*/
|
|
6
14
|
scan(): Contract;
|
|
7
15
|
private extractMethodsFromDeclaration;
|
|
8
16
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Scanner.d.ts","sourceRoot":"","sources":["../../../../src/cli/analyzeUsage/core/Scanner.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,UAAU,EAAc,MAAM,UAAU,CAAC;AAExD,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,UAAU,CAAC;AAEzD,qBAAa,OAAO;
|
|
1
|
+
{"version":3,"file":"Scanner.d.ts","sourceRoot":"","sources":["../../../../src/cli/analyzeUsage/core/Scanner.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,UAAU,EAAc,MAAM,UAAU,CAAC;AAExD,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,UAAU,CAAC;AAEzD,4EAA4E;AAC5E,qBAAa,OAAO;IAIJ,OAAO,CAAC,aAAa;IAHjC;;OAEG;gBACiB,aAAa,EAAE,UAAU;IAE7C;;;OAGG;IACI,IAAI,IAAI,QAAQ;IA4CvB,OAAO,CAAC,6BAA6B;IA0CrC;;;OAGG;IACH,OAAO,CAAC,WAAW;IAwBnB,OAAO,CAAC,cAAc;CAGzB"}
|
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Scanner = void 0;
|
|
4
4
|
const ts_morph_1 = require("ts-morph");
|
|
5
|
+
/** Сканер экспортов сгенерированного API-файла для построения контракта. */
|
|
5
6
|
class Scanner {
|
|
6
7
|
generatedFile;
|
|
8
|
+
/**
|
|
9
|
+
* @param generatedFile сгенерированный исходный файл API
|
|
10
|
+
*/
|
|
7
11
|
constructor(generatedFile) {
|
|
8
12
|
this.generatedFile = generatedFile;
|
|
9
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Сканирует экспорты файла и собирает контракт сервисов, моделей и схем.
|
|
16
|
+
* @returns контракт сгенерированного API
|
|
17
|
+
*/
|
|
10
18
|
scan() {
|
|
11
19
|
const exports = this.generatedFile.getExportedDeclarations();
|
|
12
20
|
console.log(`DEBUG SCANNER: File exports:`, Array.from(exports.keys()));
|
|
@@ -102,6 +110,8 @@ class Scanner {
|
|
|
102
110
|
name,
|
|
103
111
|
params: sig?.getParameters().map(p => ({
|
|
104
112
|
name: p.getName(),
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
114
|
+
// @ts-ignore
|
|
105
115
|
isOptional: p.isOptional(),
|
|
106
116
|
type: p.getTypeAtLocation(node).getText(),
|
|
107
117
|
})) || [],
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import type { ProjectContext } from '../core/ProjectContext';
|
|
2
2
|
import type { Contract, Finding, Rule, Stats } from '../types';
|
|
3
|
+
/** Правило проверки использования createClient и ClientOptions в потребителях API. */
|
|
3
4
|
export declare class ClientRule implements Rule {
|
|
5
|
+
/**
|
|
6
|
+
* Проверяет вызовы createClient и соответствие ClientOptions.
|
|
7
|
+
* @param context контекст проекта
|
|
8
|
+
* @param contract контракт сгенерированного API
|
|
9
|
+
* @param stats накопительная статистика использования
|
|
10
|
+
* @returns список найденных проблем
|
|
11
|
+
*/
|
|
4
12
|
check(context: ProjectContext, contract: Contract, stats: Stats): Promise<Finding[]>;
|
|
5
13
|
}
|
|
6
14
|
//# sourceMappingURL=ClientRule.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClientRule.d.ts","sourceRoot":"","sources":["../../../../src/cli/analyzeUsage/rules/ClientRule.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAE/D,qBAAa,UAAW,YAAW,IAAI;
|
|
1
|
+
{"version":3,"file":"ClientRule.d.ts","sourceRoot":"","sources":["../../../../src/cli/analyzeUsage/rules/ClientRule.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAE/D,sFAAsF;AACtF,qBAAa,UAAW,YAAW,IAAI;IACnC;;;;;;OAMG;IACG,KAAK,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CA4E7F"}
|
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ClientRule = void 0;
|
|
4
4
|
const ts_morph_1 = require("ts-morph");
|
|
5
|
+
/** Правило проверки использования createClient и ClientOptions в потребителях API. */
|
|
5
6
|
class ClientRule {
|
|
7
|
+
/**
|
|
8
|
+
* Проверяет вызовы createClient и соответствие ClientOptions.
|
|
9
|
+
* @param context контекст проекта
|
|
10
|
+
* @param contract контракт сгенерированного API
|
|
11
|
+
* @param stats накопительная статистика использования
|
|
12
|
+
* @returns список найденных проблем
|
|
13
|
+
*/
|
|
6
14
|
async check(context, contract, stats) {
|
|
7
15
|
const findings = [];
|
|
8
16
|
const checker = context.getTypeChecker();
|
|
@@ -47,6 +55,8 @@ class ClientRule {
|
|
|
47
55
|
continue;
|
|
48
56
|
if (expectedType) {
|
|
49
57
|
const providedType = checker.getTypeAtLocation(args[0]);
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
59
|
+
// @ts-ignore
|
|
50
60
|
if (!providedType.isAssignableTo(expectedType)) {
|
|
51
61
|
findings.push({
|
|
52
62
|
id: 'CLIENT_OPTIONS_MISMATCH',
|