Skip to content

Commit 5c4fad3

Browse files
committed
feat: align with new requirements
1 parent 24a60d0 commit 5c4fad3

File tree

11 files changed

+133
-44
lines changed

11 files changed

+133
-44
lines changed

src/apitypes/rest/rest.document.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@ import { convertObj } from 'swagger2openapi'
2020
import { REST_DOCUMENT_TYPE, REST_KIND_KEY } from './rest.consts'
2121
import type { RestDocumentInfo } from './rest.types'
2222

23-
import type { DocumentBuilder, DocumentDumper } from '../../types'
24-
import { YAML_EXPORT_GROUP_FORMAT } from '../../types'
23+
import { DocumentBuilder, DocumentDumper, YAML_EXPORT_GROUP_FORMAT } from '../../types'
2524
import { FILE_FORMAT } from '../../consts'
26-
import { getBundledFileDataWithDependencies, getDocumentTitle } from '../../utils'
25+
import { createBundlingErrorHandler, getBundledFileDataWithDependencies, getDocumentTitle } from '../../utils'
2726
import YAML from 'js-yaml'
2827

2928
const openApiDocumentMeta = (data: OpenAPIV3.Document): RestDocumentInfo => {
@@ -53,7 +52,10 @@ const openApiDocumentMeta = (data: OpenAPIV3.Document): RestDocumentInfo => {
5352
export const buildRestDocument: DocumentBuilder<OpenAPIV3.Document> = async (parsedFile, file, ctx) => {
5453
const { fileId, slug = '', publish = true, apiKind, ...fileMetadata } = file
5554

56-
const { data, dependencies } = await getBundledFileDataWithDependencies(fileId, ctx.parsedFileResolver, !!ctx.config.strictValidation)
55+
const {
56+
data,
57+
dependencies,
58+
} = await getBundledFileDataWithDependencies(fileId, ctx.parsedFileResolver, createBundlingErrorHandler(ctx, fileId))
5759

5860
let bundledFileData = data
5961

src/apitypes/rest/rest.operations.ts

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

1919
import { buildRestOperation } from './rest.operation'
20-
import type { OperationsBuilder } from '../../types'
21-
import { removeComponents, removeFirstSlash, slugify, takeIf } from '../../utils'
20+
import { OperationsBuilder } from '../../types'
21+
import { createBundlingErrorHandler, removeComponents, removeFirstSlash, slugify } from '../../utils'
2222
import { getOperationBasePath } from './rest.utils'
2323
import type * as TYPE from './rest.types'
2424
import { HASH_FLAG, INLINE_REFS_FLAG, MESSAGE_SEVERITY, NORMALIZE_OPTIONS, ORIGINS_SYMBOL } from '../../consts'
@@ -28,6 +28,7 @@ import { normalize } from '@netcracker/qubership-apihub-api-unifier'
2828

2929
export const buildRestOperations: OperationsBuilder<OpenAPIV3.Document> = async (document, ctx, debugCtx) => {
3030
const documentWithoutComponents = removeComponents(document.data)
31+
const bundlingErrorHandler = createBundlingErrorHandler(ctx, document.fileId)
3132

3233
const { effectiveDocument, refsOnlyDocument } = syncDebugPerformance('[NormalizeDocument]', () => {
3334
const effectiveDocument = normalize(
@@ -37,18 +38,8 @@ export const buildRestOperations: OperationsBuilder<OpenAPIV3.Document> = async
3738
originsFlag: ORIGINS_SYMBOL,
3839
hashFlag: HASH_FLAG,
3940
source: document.data,
40-
...takeIf({
41-
onRefResolveError: (message: string, path: PropertyKey[], ref: string) => {
42-
// console.debug([
43-
// '[Ref Resolve Error]',
44-
// `Message: ${message}`,
45-
// `JSON path: ${path}`,
46-
// `Ref: ${ref}`,
47-
// ].join('\n'))
48-
// todo is this message enough? (ErrorMessage.refNotFound)
49-
throw new Error(message)
50-
},
51-
}, !!ctx.config.strictValidation),
41+
onRefResolveError: (_: string, __: PropertyKey[], ref: string) =>
42+
bundlingErrorHandler([`The $ref "${ref}" references an invalid location in the document.`]),
5243
},
5344
) as OpenAPIV3.Document
5445
const refsOnlyDocument = normalize(

src/apitypes/unknown/unknown.document.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
import { BuildConfigFile, DocumentBuilder, DocumentDumper, File, VersionDocument } from '../../types'
18-
import { getBundledFileDataWithDependencies, getDocumentTitle } from '../../utils'
18+
import { createBundlingErrorHandler, getBundledFileDataWithDependencies, getDocumentTitle } from '../../utils'
1919
import { FILE_FORMAT } from '../../consts'
2020

2121
export const buildUnknownDocument: DocumentBuilder<string> = async (parsedFile, file, ctx) => {
@@ -33,7 +33,7 @@ export const buildUnknownDocument: DocumentBuilder<string> = async (parsedFile,
3333
const {
3434
data,
3535
dependencies: fileDependencies,
36-
} = await getBundledFileDataWithDependencies(fileId, ctx.parsedFileResolver, !!ctx.config.strictValidation)
36+
} = await getBundledFileDataWithDependencies(fileId, ctx.parsedFileResolver, createBundlingErrorHandler(ctx, fileId))
3737
bundledFileData = data
3838
dependencies = fileDependencies
3939
}

src/builder.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import type {
17+
import {
1818
BuildConfig,
1919
BuildConfigFile,
2020
BuildConfigRef,
@@ -28,6 +28,7 @@ import type {
2828
ResolvedDocuments,
2929
ResolvedOperations,
3030
ResolvedVersionOperationsHashMap,
31+
VALIDATION_RULES_SEVERITY_LEVEL_WARNING,
3132
VersionId,
3233
} from './types'
3334
import {
@@ -90,7 +91,12 @@ export class PackageVersionBuilder implements IPackageVersionBuilder {
9091

9192
constructor(config: BuildConfig, public params: BuilderParams, fileSources?: FileSourceMap) {
9293
this.apiBuilders.push(restApiBuilder, graphqlApiBuilder, textApiBuilder, unknownApiBuilder)
93-
this.config = { previousVersion: '', previousVersionPackageId: '', strictValidation: true, ...config }
94+
this.config = {
95+
previousVersion: '',
96+
previousVersionPackageId: '',
97+
validationRulesSeverity: { brokenRefs: VALIDATION_RULES_SEVERITY_LEVEL_WARNING },
98+
...config,
99+
}
94100

95101
this.params.configuration = {
96102
batchSize: DEFAULT_BATCH_SIZE,

src/components/document.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export const buildDocument = async (parsedFile: File, file: BuildConfigFile, ctx
5555

5656
return await apiBuilder.buildDocument(parsedFile, file, ctx)
5757
} catch (error) {
58-
throw new Error(`Cannot build file ${file.fileId}. ${error instanceof Error ? error.message : 'Unknown error'}`)
58+
throw new Error(`Cannot process the "${file.fileId}" document. ${error instanceof Error ? error.message : 'Unknown error'}`)
5959
}
6060
}
6161

src/types/external/config.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ export type OperationsGroupExportFormat =
2929
| typeof JSON_EXPORT_GROUP_FORMAT
3030
| typeof HTML_EXPORT_GROUP_FORMAT
3131

32+
export const VALIDATION_RULES_SEVERITY_LEVEL_ERROR = 'error'
33+
export const VALIDATION_RULES_SEVERITY_LEVEL_WARNING = 'warning'
34+
35+
export type ValidationRulesSeverityLevel =
36+
| typeof VALIDATION_RULES_SEVERITY_LEVEL_ERROR
37+
| typeof VALIDATION_RULES_SEVERITY_LEVEL_WARNING
38+
39+
export interface ValidationRulesSeverity {
40+
brokenRefs: ValidationRulesSeverityLevel
41+
}
42+
3243
export interface BuildConfig {
3344
packageId: PackageId
3445
version: VersionId // @revision for rebuild
@@ -49,7 +60,7 @@ export interface BuildConfig {
4960
metadata?: Record<string, unknown>
5061
format?: OperationsGroupExportFormat
5162

52-
strictValidation?: boolean
63+
validationRulesSeverity?: ValidationRulesSeverity
5364
}
5465

5566
export interface BuildConfigFile {

src/utils/document.ts

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import createSlug from 'slug'
1818
import {
1919
_ParsedFileResolver,
2020
ApiOperation,
21+
BuilderContext,
2122
BuildResult,
2223
FILE_KIND,
2324
FileFormat,
@@ -27,12 +28,14 @@ import {
2728
OperationsGroupExportFormat,
2829
PackageDocument,
2930
ResolvedDocument,
31+
VALIDATION_RULES_SEVERITY_LEVEL_ERROR,
32+
VALIDATION_RULES_SEVERITY_LEVEL_WARNING,
3033
VersionDocument,
3134
YAML_EXPORT_GROUP_FORMAT,
3235
} from '../types'
3336
import { bundle, Resolver } from 'api-ref-bundler'
34-
import { FILE_FORMAT_JSON, FILE_FORMAT_YAML } from '../consts'
35-
import { takeIf } from './objects'
37+
import { FILE_FORMAT_JSON, FILE_FORMAT_YAML, MESSAGE_SEVERITY } from '../consts'
38+
import { isNotEmpty } from './arrays'
3639

3740
export const EXPORT_FORMAT_TO_FILE_FORMAT = new Map<OperationsGroupExportFormat, FileFormat>([
3841
[YAML_EXPORT_GROUP_FORMAT, FILE_FORMAT_YAML],
@@ -118,24 +121,42 @@ export const getDocumentTitle = (fileId: string): string => {
118121
return fileId.substring(cutDot).split('/').pop()!.replace(/\.[^/.]+$/, '')
119122
}
120123

124+
export const createBundlingErrorHandler = (ctx: BuilderContext, fileId: FileId) => (messages: string[]): void => {
125+
switch (ctx.config.validationRulesSeverity?.brokenRefs) {
126+
case VALIDATION_RULES_SEVERITY_LEVEL_ERROR:
127+
throw new Error(messages[0])
128+
case VALIDATION_RULES_SEVERITY_LEVEL_WARNING:
129+
for (const message of messages) {
130+
ctx.notifications.push({
131+
severity: MESSAGE_SEVERITY.Error,
132+
message: message,
133+
fileId: fileId,
134+
})
135+
}
136+
}
137+
}
138+
121139
export const getBundledFileDataWithDependencies = async (
122140
fileId: FileId,
123141
parsedFileResolver: _ParsedFileResolver,
124-
throwOnBadRef: boolean,
142+
onError: (messages: string[]) => void,
125143
): Promise<{ data: any; dependencies: string[] }> => {
126144
const dependencies: string[] = []
145+
const errorMessages: string[] = []
127146

128147
const resolver: Resolver = async (filepath: string) => {
129148
const data = await parsedFileResolver(filepath)
130149

131150
if (data === null) {
151+
// can't throw the error here because it will be suppressed: https://github.com/udamir/api-ref-bundler/blob/0.4.0/src/resolver.ts#L33
152+
errorMessages.push(`Unable to resolve the file "${filepath}" because it does not exist.`)
132153
return {}
133154
}
134155

135-
// todo: this error has no effect because it is suppressed here: https://github.com/udamir/api-ref-bundler/blob/master/src/resolver.ts#L33
136-
// move this throw to bundler hooks or you'll see just "Cannot resolve: filename" message in case of wrong file kind
137156
if (data.kind !== FILE_KIND.TEXT) {
138-
throw new Error(`Dependency with path ${filepath} is not a text file`)
157+
// can't throw the error here because it will be suppressed: https://github.com/udamir/api-ref-bundler/blob/0.4.0/src/resolver.ts#L33
158+
errorMessages.push(`Unable to resolve the file "${filepath}" because it is not a valid text file.`)
159+
return {}
139160
}
140161

141162
if (filepath !== fileId) {
@@ -145,14 +166,11 @@ export const getBundledFileDataWithDependencies = async (
145166
return data.data
146167
}
147168

148-
const bundledFileData = await bundle(fileId, resolver, {
149-
hooks: {
150-
...takeIf(
151-
{ onError: (message: string) => { throw new Error(message) } },
152-
throwOnBadRef,
153-
),
154-
},
155-
})
169+
const bundledFileData = await bundle(fileId, resolver)
170+
171+
if (isNotEmpty(errorMessages)) {
172+
onError(errorMessages)
173+
}
156174

157175
return { data: bundledFileData, dependencies: dependencies }
158176
}
4.38 KB
Loading
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"packageId": "reference-bundling",
3+
"apiType": "rest",
4+
"version": "v1",
5+
"files": [
6+
{
7+
"fileId": "openapi.yaml",
8+
"publish": true,
9+
"labels": [],
10+
"commitId": "6c778b1f44200bd19944a6a8eac10a4e5a21a1xd"
11+
},
12+
{
13+
"fileId": "Test.png",
14+
"publish": true,
15+
"labels": [],
16+
"commitId": "6c778b1f44200bd19944a6a8eac10a4e5a21a1xd"
17+
}
18+
]
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
openapi: 3.0.1
2+
info:
3+
title: API
4+
version: 1.0.0
5+
paths:
6+
/users:
7+
get:
8+
responses:
9+
'200':
10+
description: description
11+
content:
12+
application/json:
13+
schema:
14+
type: array
15+
items:
16+
$ref: './Test.png'

0 commit comments

Comments
 (0)