Skip to content

Commit 4f2ba98

Browse files
committed
Merge branch 'release'
2 parents 1b19948 + 7050ba7 commit 4f2ba98

40 files changed

+607
-305
lines changed

package-lock.json

Lines changed: 22 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@netcracker/qubership-apihub-api-processor",
3-
"version": "3.1.0",
3+
"version": "4.0.0",
44
"description": "",
55
"license": "Apache-2.0",
66
"module": "dist/esm/src/index.js",
@@ -28,14 +28,11 @@
2828
"operation:test": "node ./test/operation.js",
2929
"profile": "node --inspect-brk ./test/profile.js",
3030
"test:coverage": "jest --verbose --coverage",
31-
"feature-start": "feature-start --featureName",
32-
"feature-finish": "feature-finish",
33-
"release-start": "release-start",
34-
"release-finish": "release-finish"
31+
"update-lock-file": "update-lock-file @netcracker"
3532
},
3633
"dependencies": {
37-
"@netcracker/qubership-apihub-api-diff": "1.1.0",
38-
"@netcracker/qubership-apihub-api-unifier": "1.0.4",
34+
"@netcracker/qubership-apihub-api-diff": "2.0.0",
35+
"@netcracker/qubership-apihub-api-unifier": "2.0.0",
3936
"@netcracker/qubership-apihub-json-crawl": "1.0.4",
4037
"@netcracker/qubership-apihub-graphapi": "1.0.8",
4138
"adm-zip": "0.5.10",
@@ -52,7 +49,7 @@
5249
"swagger2openapi": "^7.0.8"
5350
},
5451
"devDependencies": {
55-
"@netcracker/qubership-apihub-npm-gitflow": "2.2.2",
52+
"@netcracker/qubership-apihub-npm-gitflow": "3.0.1",
5653
"@types/adm-zip": "0.5.7",
5754
"@types/jest": "^29.5.12",
5855
"@types/js-yaml": "^4.0.5",

src/apitypes/rest/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { OpenAPIV3 } from 'openapi-types'
1919
import { buildRestDocument, dumpRestDocument } from './rest.document'
2020
import { REST_API_TYPE, REST_DOCUMENT_TYPE } from './rest.consts'
2121
import { compareRestOperationsData } from './rest.changes'
22-
import { buildRestOperations } from './rest.operations'
22+
import { buildRestOperations, createNormalizedOperationId } from './rest.operations'
2323
import { parseRestFile } from './rest.parser'
2424

2525
import { ApiBuilder } from '../../types'
@@ -34,4 +34,5 @@ export const restApiBuilder: ApiBuilder<OpenAPIV3.Document> = {
3434
buildOperations: buildRestOperations,
3535
dumpDocument: dumpRestDocument,
3636
compareOperationsData: compareRestOperationsData,
37+
createNormalizedOperationId: createNormalizedOperationId,
3738
}

src/apitypes/rest/rest.changes.ts

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,20 @@
1616

1717
import { RestOperationData, VersionRestOperation } from './rest.types'
1818
import { areDeprecatedOriginsNotEmpty, isOperationRemove, removeComponents } from '../../utils'
19-
import { apiDiff, breaking, COMPARE_MODE_OPERATION, Diff, DiffAction, semiBreaking } from '@netcracker/qubership-apihub-api-diff'
19+
import {
20+
apiDiff,
21+
breaking,
22+
COMPARE_MODE_OPERATION,
23+
Diff,
24+
DiffAction,
25+
risky,
26+
} from '@netcracker/qubership-apihub-api-diff'
2027
import { MESSAGE_SEVERITY, NORMALIZE_OPTIONS, ORIGINS_SYMBOL } from '../../consts'
21-
import { BREAKING_CHANGE_TYPE, CompareOperationsPairContext, SEMI_BREAKING_CHANGE_TYPE } from '../../types'
28+
import {
29+
BREAKING_CHANGE_TYPE,
30+
CompareOperationsPairContext,
31+
RISKY_CHANGE_TYPE,
32+
} from '../../types'
2233
import { isObject } from '@netcracker/qubership-apihub-json-crawl'
2334
import { areDeclarationPathsEqual } from '../../utils/path'
2435
import { JSON_SCHEMA_PROPERTY_DEPRECATED, pathItemToFullPath, resolveOrigins } from '@netcracker/qubership-apihub-api-unifier'
@@ -48,7 +59,7 @@ export const compareRestOperationsData = async (current: VersionRestOperation |
4859
normalizedResult: true,
4960
beforeSource: previous?.data,
5061
afterSource: current?.data,
51-
}
62+
},
5263
)
5364
const olnyBreaking = diffResult.diffs.filter((diff) => diff.type === breaking)
5465
if (olnyBreaking.length > 0 && previous?.operationId) {
@@ -61,7 +72,7 @@ async function reclassifyBreakingChanges(
6172
operationId: string,
6273
mergedJso: unknown,
6374
diffs: Diff[],
64-
ctx: CompareOperationsPairContext
75+
ctx: CompareOperationsPairContext,
6576
): Promise<void> {
6677
if (!ctx.previousVersion || !ctx.previousPackageId) {
6778
return
@@ -71,6 +82,7 @@ async function reclassifyBreakingChanges(
7182
return
7283
}
7384
previosVersionDeprecations.operations[0]
85+
7486
const previousOperation = previosVersionDeprecations.operations[0]
7587

7688
if (!previousOperation?.deprecatedItems) { return }
@@ -82,7 +94,7 @@ async function reclassifyBreakingChanges(
8294

8395
const deprecatedInVersionsCount = previousOperation?.deprecatedInPreviousVersions?.length ?? 0
8496
if (isOperationRemove(diff) && deprecatedInVersionsCount > 1) {
85-
diff.type = semiBreaking
97+
diff.type = risky
8698
continue
8799
}
88100

@@ -93,7 +105,7 @@ async function reclassifyBreakingChanges(
93105
if (!isObject(diff.beforeNormalizedValue)) {
94106
ctx.notifications.push({
95107
severity: MESSAGE_SEVERITY.Error,
96-
message: '[Semi-breaking validation] Something wrong with beforeNormalizedValue from diff',
108+
message: '[Risky validation] Something wrong with beforeNormalizedValue from diff',
97109
})
98110
continue
99111
}
@@ -102,7 +114,7 @@ async function reclassifyBreakingChanges(
102114
if (!areDeprecatedOriginsNotEmpty(diff.beforeNormalizedValue)) {
103115
ctx.notifications.push({
104116
severity: MESSAGE_SEVERITY.Error,
105-
message: '[Semi-breaking validation] Something wrong with origins',
117+
message: '[Risky validation] Something wrong with origins',
106118
})
107119
continue
108120
}
@@ -125,16 +137,16 @@ async function reclassifyBreakingChanges(
125137
}
126138

127139
if (deprecatedItem && deprecatedItem?.deprecatedInPreviousVersions?.length > 1) {
128-
diff.type = semiBreaking
140+
diff.type = risky
129141
}
130142
}
131-
// mark removed required status of the property as semi-breaking
143+
// mark removed required status of the property as risky
132144
if (diffs.length) {
133145
const requiredProperties = findRequiredRemovedProperties(mergedJso, diffs)
134146

135147
requiredProperties?.forEach(prop => {
136-
if (prop.propDiff.type === SEMI_BREAKING_CHANGE_TYPE && prop.requiredDiff?.type === BREAKING_CHANGE_TYPE) {
137-
prop.requiredDiff.type = semiBreaking
148+
if (prop.propDiff.type === RISKY_CHANGE_TYPE && prop.requiredDiff?.type === BREAKING_CHANGE_TYPE) {
149+
prop.requiredDiff.type = risky
138150
}
139151
})
140152
}

src/apitypes/rest/rest.operations.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,20 @@
1717
import { OpenAPIV3 } from 'openapi-types'
1818

1919
import { buildRestOperation } from './rest.operation'
20-
import { OperationsBuilder } from '../../types'
21-
import { createBundlingErrorHandler, removeComponents, removeFirstSlash, slugify } from '../../utils'
20+
import { OperationIdNormalizer, OperationsBuilder } from '../../types'
21+
import {
22+
createBundlingErrorHandler,
23+
IGNORE_PATH_PARAM_UNIFIED_PLACEHOLDER,
24+
removeComponents,
25+
removeFirstSlash,
26+
slugify,
27+
} from '../../utils'
2228
import { getOperationBasePath } from './rest.utils'
2329
import type * as TYPE from './rest.types'
2430
import { HASH_FLAG, INLINE_REFS_FLAG, MESSAGE_SEVERITY, NORMALIZE_OPTIONS, ORIGINS_SYMBOL } from '../../consts'
2531
import { asyncFunction } from '../../utils/async'
2632
import { logLongBuild, syncDebugPerformance } from '../../utils/logs'
27-
import { normalize } from '@netcracker/qubership-apihub-api-unifier'
33+
import { normalize, RefErrorType } from '@netcracker/qubership-apihub-api-unifier'
2834

2935
export const buildRestOperations: OperationsBuilder<OpenAPIV3.Document> = async (document, ctx, debugCtx) => {
3036
const documentWithoutComponents = removeComponents(document.data)
@@ -38,8 +44,8 @@ export const buildRestOperations: OperationsBuilder<OpenAPIV3.Document> = async
3844
originsFlag: ORIGINS_SYMBOL,
3945
hashFlag: HASH_FLAG,
4046
source: document.data,
41-
onRefResolveError: (_: string, __: PropertyKey[], ref: string) =>
42-
bundlingErrorHandler([`The $ref "${ref}" references an invalid location in the document.`]),
47+
onRefResolveError: (message: string, _path: PropertyKey[], _ref: string, errorType: RefErrorType) =>
48+
bundlingErrorHandler([{ message, errorType }]),
4349
},
4450
) as OpenAPIV3.Document
4551
const refsOnlyDocument = normalize(
@@ -106,3 +112,8 @@ export const buildRestOperations: OperationsBuilder<OpenAPIV3.Document> = async
106112
}
107113
return operations
108114
}
115+
116+
export const createNormalizedOperationId: OperationIdNormalizer = (operation) => {
117+
const { metadata: { path, method } } = operation
118+
return slugify(`${path}-${method}`, [], IGNORE_PATH_PARAM_UNIFIED_PLACEHOLDER)
119+
}

src/apitypes/rest/rest.types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ import type { OpenAPIV3 } from 'openapi-types'
1818

1919
import type { ApiOperation, NotificationMessage, VersionDocument } from '../../types'
2020
import { REST_DOCUMENT_TYPE, REST_KIND_KEY, REST_SCOPES } from './rest.consts'
21+
import { NormalizedPath } from '../../utils'
2122

2223
export type RestScopeType = keyof typeof REST_SCOPES
2324
export type RestDocumentType = (typeof REST_DOCUMENT_TYPE)[keyof typeof REST_DOCUMENT_TYPE]
2425
export type CustomTags = Record<string, unknown>
2526

2627
export interface RestOperationMeta {
27-
path: string // `/packages/*/version/*`
28+
path: NormalizedPath // `/packages/*/version/*`
2829
originalPath: string // `/packages/{packageId}/version/{version}`
2930
method: OpenAPIV3.HttpMethods // `get` | `post` | ...
3031
tags?: string[] // operations tags

src/builder.ts

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@ import {
2727
ResolvedDeprecatedOperations,
2828
ResolvedDocuments,
2929
ResolvedOperations,
30-
ResolvedVersionOperationsHashMap,
31-
VALIDATION_RULES_SEVERITY_LEVEL_WARNING,
3230
VersionId,
31+
VersionsComparison,
3332
} from './types'
3433
import {
3534
ApiBuilder,
@@ -46,7 +45,6 @@ import {
4645
OperationChanges,
4746
VersionCache,
4847
VersionDocument,
49-
VersionsComparisonDto,
5048
} from './types/internal'
5149
import type { NotificationMessage, PackageConfig } from './types/package'
5250
import { graphqlApiBuilder, REST_API_TYPE, restApiBuilder, textApiBuilder, unknownApiBuilder } from './apitypes'
@@ -81,7 +79,7 @@ export class PackageVersionBuilder implements IPackageVersionBuilder {
8179
apiBuilders: ApiBuilder[] = []
8280
documents = new Map<string, VersionDocument>()
8381
operations = new Map<string, ApiOperation>()
84-
comparisons: VersionsComparisonDto[] = []
82+
comparisons: VersionsComparison[] = []
8583

8684
versionsCache = new Map<string, VersionCache>()
8785
referencesCache = new Map<string, BuildConfigRef[]>()
@@ -288,7 +286,10 @@ export class PackageVersionBuilder implements IPackageVersionBuilder {
288286
packageId = packageId ?? this.config.packageId
289287

290288
if (this.canBeResolvedLocally(version, packageId)) {
291-
const currentOperations = operationIds ? this.operationList.filter(({ operationId }) => operationIds.includes(operationId)) : this.operationList
289+
const currentApiTypeOperations = this.operationList.filter((operation) => operation.apiType === apiType)
290+
const currentOperations = operationIds
291+
? currentApiTypeOperations.filter(({ operationId }) => operationIds.includes(operationId))
292+
: currentApiTypeOperations
292293
return { operations: currentOperations }
293294
}
294295

@@ -417,6 +418,8 @@ export class PackageVersionBuilder implements IPackageVersionBuilder {
417418
throw new Error('No versionResolver provided')
418419
}
419420

421+
// includeOperations=true is only used to extract unique apiTypes (see getUniqueApiTypesFromVersions)
422+
// the operations map itself is no longer used in processor
420423
const versionContent = await versionResolver(packageId, version, true)
421424

422425
if (!versionContent) {
@@ -473,7 +476,10 @@ export class PackageVersionBuilder implements IPackageVersionBuilder {
473476
return []
474477
}
475478

476-
const referencesCache: BuildConfigRef[] = Object.values(versionReferences.packages ?? {}).filter(pack => !pack.deletedAt).map(pack => ({ refId: pack.refId, version: pack.version }))
479+
const referencesCache: BuildConfigRef[] = Object.values(versionReferences.packages ?? {}).filter(pack => !pack.deletedAt).map(pack => ({
480+
refId: pack.refId,
481+
version: pack.version,
482+
}))
477483
this.referencesCache.set(compositeKey, referencesCache)
478484

479485
return referencesCache
@@ -492,10 +498,9 @@ export class PackageVersionBuilder implements IPackageVersionBuilder {
492498
const operationsTypes: OperationTypes[] = []
493499

494500
for (const apiType of this.existingOperationsApiTypes) {
495-
const operationsHashMap = this.operationsHashMapByApiType(apiType)
496501
operationsTypes.push({
497502
apiType: apiType,
498-
operations: operationsHashMap,
503+
operationsCount: this.operations.size,
499504
})
500505
}
501506

@@ -508,18 +513,6 @@ export class PackageVersionBuilder implements IPackageVersionBuilder {
508513
return new Set(apiTypes)
509514
}
510515

511-
private operationsHashMapByApiType(operationsApiType: OperationsApiType): ResolvedVersionOperationsHashMap {
512-
const hashMap: ResolvedVersionOperationsHashMap = {}
513-
514-
for (const { apiType, operationId, dataHash } of this.operations.values()) {
515-
if (apiType === operationsApiType) {
516-
hashMap[operationId] = dataHash
517-
}
518-
}
519-
520-
return hashMap
521-
}
522-
523516
async parseFile(fileId: string, source: Blob): Promise<File | null> {
524517
if (this.parsedFiles.has(fileId)) {
525518
return this.parsedFiles.get(fileId) ?? null

0 commit comments

Comments
 (0)