@conduit-client/model 3.9.0 → 3.11.0
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/dist/types/v1/parser/__tests__/test-utils.d.ts +2 -0
- package/dist/types/v1/parser/swagger/SwaggerAPI.d.ts +17 -1
- package/dist/types/v1/parser/swagger/__tests__/source-position-map.spec.d.ts +1 -0
- package/dist/types/v1/parser/swagger/endpoints/swagger-operation.d.ts +2 -4
- package/dist/types/v1/parser/swagger/parser.d.ts +2 -0
- package/dist/types/v1/parser/swagger/source-position-map.d.ts +39 -2
- package/dist/types/v1/parser/swagger/swagger-utils.d.ts +16 -2
- package/dist/types/v1/parser/swagger/types/SwaggerBaseType.d.ts +2 -4
- package/dist/v1/index.js +312 -59
- package/dist/v1/index.js.map +1 -1
- package/package.json +3 -3
package/dist/v1/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import * as url from "url";
|
|
|
7
7
|
import amf from "amf-client-js";
|
|
8
8
|
import path from "path";
|
|
9
9
|
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
10
|
+
import { MissingPointerError, ResolverError } from "@apidevtools/json-schema-ref-parser";
|
|
10
11
|
const BindingTypesEnum = ["wire", "imperative", "imperative-legacy", "mutation"];
|
|
11
12
|
class BaseTypeRegistry extends Map {
|
|
12
13
|
nameOf(t) {
|
|
@@ -13338,6 +13339,7 @@ const annotationSchema = z.object({
|
|
|
13338
13339
|
});
|
|
13339
13340
|
class SwaggerBaseType {
|
|
13340
13341
|
constructor(api, schema2, schemaName, typeRegistry, factory, logger, fileParserLogger, jsonPath) {
|
|
13342
|
+
var _a;
|
|
13341
13343
|
this.api = api;
|
|
13342
13344
|
this.schema = schema2;
|
|
13343
13345
|
this.schemaName = schemaName;
|
|
@@ -13347,13 +13349,18 @@ class SwaggerBaseType {
|
|
|
13347
13349
|
this.fileParserLogger = fileParserLogger;
|
|
13348
13350
|
this.resolved = false;
|
|
13349
13351
|
this.parsedExtensions = { type: "unidentifiable" };
|
|
13352
|
+
const defaultPosition = {
|
|
13353
|
+
line: 0,
|
|
13354
|
+
column: 0,
|
|
13355
|
+
filePath: ((_a = api.sourceUrl) == null ? void 0 : _a.pathname) ?? ""
|
|
13356
|
+
};
|
|
13350
13357
|
if (jsonPath) {
|
|
13351
|
-
this.schemaPosition = api.getPosition(jsonPath) ??
|
|
13358
|
+
this.schemaPosition = api.getPosition(jsonPath) ?? defaultPosition;
|
|
13352
13359
|
} else if (schemaName) {
|
|
13353
13360
|
const defaultPath = `components/schemas/${schemaName}`;
|
|
13354
|
-
this.schemaPosition = api.getPosition(defaultPath) ??
|
|
13361
|
+
this.schemaPosition = api.getPosition(defaultPath) ?? defaultPosition;
|
|
13355
13362
|
} else {
|
|
13356
|
-
this.schemaPosition =
|
|
13363
|
+
this.schemaPosition = defaultPosition;
|
|
13357
13364
|
}
|
|
13358
13365
|
}
|
|
13359
13366
|
resolve() {
|
|
@@ -13516,6 +13523,12 @@ class SwaggerNilTypeImpl extends SwaggerBaseType {
|
|
|
13516
13523
|
function isReferenceObject(obj) {
|
|
13517
13524
|
return obj !== null && typeof obj === "object" && "$ref" in obj;
|
|
13518
13525
|
}
|
|
13526
|
+
function isSchemaObject(obj) {
|
|
13527
|
+
return obj !== null && typeof obj === "object" && !("$ref" in obj) && ("type" in obj || "properties" in obj || "allOf" in obj || "anyOf" in obj || "oneOf" in obj || "items" in obj);
|
|
13528
|
+
}
|
|
13529
|
+
function isOpenAPISchema(obj) {
|
|
13530
|
+
return isSchemaObject(obj) || isReferenceObject(obj);
|
|
13531
|
+
}
|
|
13519
13532
|
function isArraySchema(schema2) {
|
|
13520
13533
|
return schema2.type === "array";
|
|
13521
13534
|
}
|
|
@@ -13590,6 +13603,14 @@ function mapScalarType(schema2) {
|
|
|
13590
13603
|
}
|
|
13591
13604
|
}
|
|
13592
13605
|
function getRefTypeName(ref) {
|
|
13606
|
+
const hashIndex = ref.lastIndexOf("#");
|
|
13607
|
+
if (hashIndex !== -1) {
|
|
13608
|
+
const fragment = ref.substring(hashIndex + 1);
|
|
13609
|
+
const parts2 = fragment.split("/").filter((p) => p !== "");
|
|
13610
|
+
if (parts2.length > 0) {
|
|
13611
|
+
return parts2[parts2.length - 1];
|
|
13612
|
+
}
|
|
13613
|
+
}
|
|
13593
13614
|
const parts = ref.split("/");
|
|
13594
13615
|
return parts[parts.length - 1];
|
|
13595
13616
|
}
|
|
@@ -13607,6 +13628,28 @@ function getEnumValues(schema2, schemaName) {
|
|
|
13607
13628
|
);
|
|
13608
13629
|
});
|
|
13609
13630
|
}
|
|
13631
|
+
const OPENAPI_DOCUMENT_PROPERTIES = /* @__PURE__ */ new Set([
|
|
13632
|
+
"openapi",
|
|
13633
|
+
"info",
|
|
13634
|
+
"servers",
|
|
13635
|
+
"paths",
|
|
13636
|
+
"components",
|
|
13637
|
+
"security",
|
|
13638
|
+
"tags",
|
|
13639
|
+
"externalDocs",
|
|
13640
|
+
"webhooks",
|
|
13641
|
+
"jsonSchemaDialect"
|
|
13642
|
+
]);
|
|
13643
|
+
function extractRootLevelSchemas(file) {
|
|
13644
|
+
const schemas2 = {};
|
|
13645
|
+
for (const [key, value] of Object.entries(file)) {
|
|
13646
|
+
if (OPENAPI_DOCUMENT_PROPERTIES.has(key) || key.startsWith("x-")) continue;
|
|
13647
|
+
if (isOpenAPISchema(value)) {
|
|
13648
|
+
schemas2[key] = value;
|
|
13649
|
+
}
|
|
13650
|
+
}
|
|
13651
|
+
return schemas2;
|
|
13652
|
+
}
|
|
13610
13653
|
class SwaggerEnumerableScalarType extends SwaggerBaseType {
|
|
13611
13654
|
typeResolve() {
|
|
13612
13655
|
if (this.schema.enum && this.schema.enum.length > 0) {
|
|
@@ -13894,6 +13937,12 @@ class SwaggerRefTypeImpl extends SwaggerBaseType {
|
|
|
13894
13937
|
};
|
|
13895
13938
|
this.resolved = false;
|
|
13896
13939
|
this.refString = this.schema.$ref || "";
|
|
13940
|
+
if (this.schemaPosition.line === 0 && this.schemaPosition.column === 0 && this.refString && this.api) {
|
|
13941
|
+
const refPosition = this.api.getRefPosition(this.refString);
|
|
13942
|
+
if (refPosition) {
|
|
13943
|
+
this.schemaPosition = refPosition;
|
|
13944
|
+
}
|
|
13945
|
+
}
|
|
13897
13946
|
}
|
|
13898
13947
|
typeResolve() {
|
|
13899
13948
|
if (this.refString) {
|
|
@@ -13905,7 +13954,7 @@ class SwaggerRefTypeImpl extends SwaggerBaseType {
|
|
|
13905
13954
|
inheritedType.resolve();
|
|
13906
13955
|
this.$ref = inheritedType;
|
|
13907
13956
|
} else {
|
|
13908
|
-
const errorMessage = `Failed to resolve $ref: ${
|
|
13957
|
+
const errorMessage = `Failed to resolve $ref: ${this.refString}`;
|
|
13909
13958
|
this.fileParserLogger.error(this.schemaPosition, errorMessage);
|
|
13910
13959
|
throw new Error(errorMessage);
|
|
13911
13960
|
}
|
|
@@ -14133,7 +14182,7 @@ function swaggerTypeFactory(api, schema2, schemaName, typeRegistry, logger, file
|
|
|
14133
14182
|
}
|
|
14134
14183
|
class SwaggerBaseOperation {
|
|
14135
14184
|
constructor(operation, methodStr, swaggerTypeFactory2, typeRegistry, logger, fileParserLogger, endpoint, server) {
|
|
14136
|
-
var _a, _b;
|
|
14185
|
+
var _a, _b, _c;
|
|
14137
14186
|
this.operation = operation;
|
|
14138
14187
|
this.methodStr = methodStr;
|
|
14139
14188
|
this.swaggerTypeFactory = swaggerTypeFactory2;
|
|
@@ -14145,7 +14194,12 @@ class SwaggerBaseOperation {
|
|
|
14145
14194
|
this.defaults = endpoint.api.defaults;
|
|
14146
14195
|
this.method = methodStr.toUpperCase();
|
|
14147
14196
|
const jsonPath = `paths/${endpoint.path}/${methodStr}`;
|
|
14148
|
-
|
|
14197
|
+
const defaultPosition = {
|
|
14198
|
+
line: 0,
|
|
14199
|
+
column: 0,
|
|
14200
|
+
filePath: ((_a = endpoint.api.sourceUrl) == null ? void 0 : _a.pathname) ?? "Unknown File"
|
|
14201
|
+
};
|
|
14202
|
+
this.position = ((_c = (_b = endpoint.api).getPosition) == null ? void 0 : _c.call(_b, jsonPath)) ?? defaultPosition;
|
|
14149
14203
|
const extensionsRaw = extractExtensions(operation);
|
|
14150
14204
|
this.operationId = operation.operationId;
|
|
14151
14205
|
this.operationSchemaBuilder = new OperationSchemaBuilder(
|
|
@@ -14192,10 +14246,14 @@ ${message}`);
|
|
|
14192
14246
|
headers: {}
|
|
14193
14247
|
};
|
|
14194
14248
|
const parameters = this.operation.parameters || [];
|
|
14195
|
-
for (
|
|
14196
|
-
if (isReferenceObject(param))
|
|
14249
|
+
for (let param of parameters) {
|
|
14250
|
+
if (isReferenceObject(param)) {
|
|
14251
|
+
param = this.endpoint.api.resolveRefTargetPath(
|
|
14252
|
+
param.$ref
|
|
14253
|
+
);
|
|
14254
|
+
}
|
|
14197
14255
|
const paramType = this.swaggerTypeFactory(
|
|
14198
|
-
|
|
14256
|
+
this.endpoint.api,
|
|
14199
14257
|
param.schema || { type: "string" },
|
|
14200
14258
|
void 0,
|
|
14201
14259
|
this.typeRegistry,
|
|
@@ -14224,12 +14282,17 @@ ${message}`);
|
|
|
14224
14282
|
}
|
|
14225
14283
|
}
|
|
14226
14284
|
if (this.operation.requestBody) {
|
|
14227
|
-
|
|
14285
|
+
let requestBody = this.operation.requestBody;
|
|
14286
|
+
if (isReferenceObject(requestBody)) {
|
|
14287
|
+
requestBody = this.endpoint.api.resolveRefTargetPath(
|
|
14288
|
+
requestBody.$ref
|
|
14289
|
+
);
|
|
14290
|
+
}
|
|
14228
14291
|
if (requestBody == null ? void 0 : requestBody.content) {
|
|
14229
14292
|
for (const [mediaType, content] of Object.entries(requestBody.content)) {
|
|
14230
14293
|
if (content.schema) {
|
|
14231
14294
|
const dataType = this.swaggerTypeFactory(
|
|
14232
|
-
|
|
14295
|
+
this.endpoint.api,
|
|
14233
14296
|
content.schema,
|
|
14234
14297
|
void 0,
|
|
14235
14298
|
this.typeRegistry,
|
|
@@ -14251,18 +14314,28 @@ ${message}`);
|
|
|
14251
14314
|
buildResponses() {
|
|
14252
14315
|
const responses = [];
|
|
14253
14316
|
const opResponses = this.operation.responses || {};
|
|
14254
|
-
for (const [statusCode,
|
|
14255
|
-
|
|
14317
|
+
for (const [statusCode, opResponse] of Object.entries(opResponses)) {
|
|
14318
|
+
let responseObj = opResponse;
|
|
14319
|
+
if (isReferenceObject(responseObj)) {
|
|
14320
|
+
responseObj = this.endpoint.api.resolveRefTargetPath(
|
|
14321
|
+
responseObj.$ref
|
|
14322
|
+
);
|
|
14323
|
+
}
|
|
14256
14324
|
const response = {
|
|
14257
14325
|
statusCode,
|
|
14258
14326
|
payloads: [],
|
|
14259
14327
|
headers: {}
|
|
14260
14328
|
};
|
|
14261
14329
|
if (responseObj.headers) {
|
|
14262
|
-
for (const [headerName,
|
|
14263
|
-
|
|
14330
|
+
for (const [headerName, headerValue] of Object.entries(responseObj.headers)) {
|
|
14331
|
+
let headerObj = headerValue;
|
|
14332
|
+
if (isReferenceObject(headerObj)) {
|
|
14333
|
+
headerObj = this.endpoint.api.resolveRefTargetPath(
|
|
14334
|
+
headerObj.$ref
|
|
14335
|
+
);
|
|
14336
|
+
}
|
|
14264
14337
|
const headerType = this.swaggerTypeFactory(
|
|
14265
|
-
|
|
14338
|
+
this.endpoint.api,
|
|
14266
14339
|
headerObj.schema || { type: "string" },
|
|
14267
14340
|
void 0,
|
|
14268
14341
|
this.typeRegistry,
|
|
@@ -14280,7 +14353,7 @@ ${message}`);
|
|
|
14280
14353
|
for (const [mediaType, content] of Object.entries(responseObj.content)) {
|
|
14281
14354
|
if (content.schema) {
|
|
14282
14355
|
const dataType = this.swaggerTypeFactory(
|
|
14283
|
-
|
|
14356
|
+
this.endpoint.api,
|
|
14284
14357
|
content.schema,
|
|
14285
14358
|
void 0,
|
|
14286
14359
|
this.typeRegistry,
|
|
@@ -14611,8 +14684,10 @@ class SwaggerBaseEndpoint {
|
|
|
14611
14684
|
this.path = pathStr;
|
|
14612
14685
|
this.uriParameters = {};
|
|
14613
14686
|
const parameters = pathItem.parameters || [];
|
|
14614
|
-
for (
|
|
14615
|
-
if (isReferenceObject(param))
|
|
14687
|
+
for (let param of parameters) {
|
|
14688
|
+
if (isReferenceObject(param)) {
|
|
14689
|
+
param = api.resolveRefTargetPath(param.$ref);
|
|
14690
|
+
}
|
|
14616
14691
|
if (param.in !== "path") continue;
|
|
14617
14692
|
const paramType = swaggerTypeFactory2(
|
|
14618
14693
|
api,
|
|
@@ -14687,46 +14762,42 @@ ${validationMessage}`);
|
|
|
14687
14762
|
}
|
|
14688
14763
|
function getSchemaPosition(subject, validationType) {
|
|
14689
14764
|
if (validationType === ValidationType.Operation) {
|
|
14690
|
-
return subject.position || { line: 0, column: 0 };
|
|
14765
|
+
return subject.position || { line: 0, column: 0, filePath: "" };
|
|
14691
14766
|
}
|
|
14692
|
-
return subject.schemaPosition || { line: 0, column: 0 };
|
|
14767
|
+
return subject.schemaPosition || { line: 0, column: 0, filePath: "" };
|
|
14693
14768
|
}
|
|
14694
|
-
function formatMessage(messages,
|
|
14695
|
-
const padding =
|
|
14769
|
+
function formatMessage(messages, level = 0) {
|
|
14770
|
+
const padding = " ".repeat(level);
|
|
14696
14771
|
return messages.reduce((result, message) => {
|
|
14697
14772
|
const position = getSchemaPosition(message.subject, message.validationType);
|
|
14698
|
-
|
|
14699
|
-
|
|
14773
|
+
const formatted = lineFormatter(position, message.message, position.filePath);
|
|
14774
|
+
const subMessages = formatMessage(message.subValidationMessages ?? [], level + 1);
|
|
14775
|
+
return `${result}${padding}- ${formatted}
|
|
14776
|
+
${subMessages}`;
|
|
14700
14777
|
}, "");
|
|
14701
14778
|
}
|
|
14702
14779
|
function isValidSwaggerAPI(api, fileParserLogger) {
|
|
14703
|
-
const
|
|
14704
|
-
return lineFormatter(pos, msg, fileParserLogger.filePath);
|
|
14705
|
-
};
|
|
14780
|
+
const defaultFilePath = fileParserLogger.filePath;
|
|
14706
14781
|
const apiValidator = buildApiValidatorFor(api);
|
|
14707
14782
|
const result = apiValidator.validate(api);
|
|
14708
14783
|
const isValid2 = result.isOk();
|
|
14709
14784
|
const messages = isValid2 ? result.value : result.error;
|
|
14710
|
-
for (const {
|
|
14711
|
-
message,
|
|
14712
|
-
subject,
|
|
14713
|
-
severity,
|
|
14714
|
-
validationType,
|
|
14715
|
-
subValidationMessages: extraValidation
|
|
14716
|
-
} of messages) {
|
|
14717
|
-
let lineMessage = message;
|
|
14718
|
-
if (extraValidation !== void 0) {
|
|
14719
|
-
const formattedValidation = `${formatMessage(extraValidation, formatter, 1)}`;
|
|
14720
|
-
lineMessage = `${lineMessage}
|
|
14721
|
-
${formattedValidation}`;
|
|
14722
|
-
}
|
|
14785
|
+
for (const { message, subject, severity, validationType, subValidationMessages } of messages) {
|
|
14723
14786
|
const position = getSchemaPosition(subject, validationType);
|
|
14787
|
+
let finalMessage = message;
|
|
14788
|
+
if (subValidationMessages !== void 0 && subValidationMessages.length > 0) {
|
|
14789
|
+
finalMessage += `
|
|
14790
|
+
${formatMessage(subValidationMessages, 1)}`;
|
|
14791
|
+
}
|
|
14792
|
+
if (position.filePath !== defaultFilePath) {
|
|
14793
|
+
finalMessage = `[${position.filePath}:${position.line}:${position.column}] ${finalMessage}`;
|
|
14794
|
+
}
|
|
14724
14795
|
if (severity === ValidationSeverity.Error) {
|
|
14725
|
-
fileParserLogger.error(position,
|
|
14796
|
+
fileParserLogger.error(position, finalMessage);
|
|
14726
14797
|
} else if (severity === ValidationSeverity.Warning) {
|
|
14727
|
-
fileParserLogger.warn(position,
|
|
14798
|
+
fileParserLogger.warn(position, finalMessage);
|
|
14728
14799
|
} else if (severity === ValidationSeverity.Info) {
|
|
14729
|
-
fileParserLogger.info(position,
|
|
14800
|
+
fileParserLogger.info(position, finalMessage);
|
|
14730
14801
|
}
|
|
14731
14802
|
}
|
|
14732
14803
|
return isValid2;
|
|
@@ -14753,12 +14824,13 @@ const oneStoreExtensionsSchema = z.object({
|
|
|
14753
14824
|
}).strict()
|
|
14754
14825
|
});
|
|
14755
14826
|
class SwaggerAPI {
|
|
14756
|
-
constructor(document, sourceUrl, services, fileParserLogger, positionMap) {
|
|
14827
|
+
constructor(document, sourceUrl, services, fileParserLogger, positionMap, $refs) {
|
|
14757
14828
|
this.document = document;
|
|
14758
14829
|
this.sourceUrl = sourceUrl;
|
|
14759
14830
|
this.services = services;
|
|
14760
14831
|
this.fileParserLogger = fileParserLogger;
|
|
14761
14832
|
this.positionMap = positionMap;
|
|
14833
|
+
this.$refs = $refs;
|
|
14762
14834
|
this.built = false;
|
|
14763
14835
|
const urlPath = sourceUrl.pathname;
|
|
14764
14836
|
this.defaultedNamespace = path.parse(urlPath).name;
|
|
@@ -14774,6 +14846,41 @@ class SwaggerAPI {
|
|
|
14774
14846
|
getPosition(jsonPath) {
|
|
14775
14847
|
return this.positionMap.get(jsonPath);
|
|
14776
14848
|
}
|
|
14849
|
+
/**
|
|
14850
|
+
* Find the position of a $ref declaration by its target value.
|
|
14851
|
+
* @param refValue - The $ref target string (e.g., "./schemas/User.yaml#/TypeThatDoesNotExist")
|
|
14852
|
+
* @returns The position where the $ref is declared, if found
|
|
14853
|
+
*/
|
|
14854
|
+
getRefPosition(refValue) {
|
|
14855
|
+
const result = this.positionMap.findRefPosition(refValue);
|
|
14856
|
+
return result == null ? void 0 : result.position;
|
|
14857
|
+
}
|
|
14858
|
+
/**
|
|
14859
|
+
* Resolve a $ref target path with respect to the directory of the source.
|
|
14860
|
+
* This is particularly necessary for relative paths since this.$refs.get() resolves
|
|
14861
|
+
* paths relative to the root file and not the ref source file.
|
|
14862
|
+
* @param refPath - The $ref target path (e.g., "./schemas/User.yaml#/User")
|
|
14863
|
+
* @returns The path from where the $ref is declared (e.g, "file:///path/to/source/./schemas/User.yaml#/User")
|
|
14864
|
+
*/
|
|
14865
|
+
resolveRefTargetPath(refTarget) {
|
|
14866
|
+
var _a;
|
|
14867
|
+
const hashIndex = refTarget.indexOf("#");
|
|
14868
|
+
const refTargetFilePath = hashIndex === -1 ? refTarget : refTarget.substring(0, hashIndex);
|
|
14869
|
+
let resolvedPath;
|
|
14870
|
+
if (!refTargetFilePath) {
|
|
14871
|
+
resolvedPath = refTarget;
|
|
14872
|
+
} else if (/^(https?|file):\/\//.test(refTargetFilePath)) {
|
|
14873
|
+
resolvedPath = refTargetFilePath;
|
|
14874
|
+
} else {
|
|
14875
|
+
const refSourceFilePath = (_a = this.positionMap.getRef(refTarget)) == null ? void 0 : _a.filePath;
|
|
14876
|
+
if (!refSourceFilePath) {
|
|
14877
|
+
throw new Error(`Failed to resolve $ref: ${refTarget}`);
|
|
14878
|
+
}
|
|
14879
|
+
const refSourceBasePath = path.dirname(refSourceFilePath);
|
|
14880
|
+
resolvedPath = path.join(refSourceBasePath, refTarget);
|
|
14881
|
+
}
|
|
14882
|
+
return this.$refs.get(resolvedPath);
|
|
14883
|
+
}
|
|
14777
14884
|
build() {
|
|
14778
14885
|
if (!this.built) {
|
|
14779
14886
|
this.built = true;
|
|
@@ -14784,9 +14891,14 @@ class SwaggerAPI {
|
|
|
14784
14891
|
}
|
|
14785
14892
|
}
|
|
14786
14893
|
buildEndpoints() {
|
|
14787
|
-
|
|
14788
|
-
|
|
14894
|
+
var _a;
|
|
14895
|
+
const paths = ((_a = this.$refs.values()[this.sourceUrl.toString()]) == null ? void 0 : _a.paths) || {};
|
|
14896
|
+
this._endpoints = Object.entries(paths).map(([pathStr, pathValue]) => {
|
|
14897
|
+
let pathItem = pathValue;
|
|
14789
14898
|
if (!pathItem) return void 0;
|
|
14899
|
+
if (isReferenceObject(pathItem)) {
|
|
14900
|
+
pathItem = this.resolveRefTargetPath(pathItem.$ref);
|
|
14901
|
+
}
|
|
14790
14902
|
return swaggerEndpointFactory(
|
|
14791
14903
|
pathStr,
|
|
14792
14904
|
pathItem,
|
|
@@ -14831,10 +14943,17 @@ servers:
|
|
|
14831
14943
|
});
|
|
14832
14944
|
}
|
|
14833
14945
|
buildTypes() {
|
|
14834
|
-
var _a;
|
|
14835
14946
|
this.services.logger.debug("SwaggerAPI - Building the type registry");
|
|
14836
14947
|
const typeRegistry = this.typeRegistry = new BaseTypeRegistry();
|
|
14837
|
-
const schemas2 = (
|
|
14948
|
+
const schemas2 = Object.values(this.$refs.values()).reduce(
|
|
14949
|
+
(acc, file) => {
|
|
14950
|
+
var _a;
|
|
14951
|
+
const componentSchemas = ((_a = file.components) == null ? void 0 : _a.schemas) ?? {};
|
|
14952
|
+
const rootSchemas = extractRootLevelSchemas(file);
|
|
14953
|
+
return { ...acc, ...componentSchemas, ...rootSchemas };
|
|
14954
|
+
},
|
|
14955
|
+
{}
|
|
14956
|
+
);
|
|
14838
14957
|
for (const [name, schema2] of Object.entries(schemas2)) {
|
|
14839
14958
|
this.services.logger.debug(`SwaggerAPI - Building Swagger Type for ${name}`);
|
|
14840
14959
|
const swaggerType = swaggerTypeFactory(
|
|
@@ -14924,6 +15043,8 @@ servers:
|
|
|
14924
15043
|
class SourcePositionMap {
|
|
14925
15044
|
constructor() {
|
|
14926
15045
|
this.positions = /* @__PURE__ */ new Map();
|
|
15046
|
+
this.fileUrls = /* @__PURE__ */ new Set();
|
|
15047
|
+
this.refTargets = /* @__PURE__ */ new Map();
|
|
14927
15048
|
}
|
|
14928
15049
|
/**
|
|
14929
15050
|
* Get the position for a given JSON path
|
|
@@ -14932,6 +15053,13 @@ class SourcePositionMap {
|
|
|
14932
15053
|
get(jsonPath) {
|
|
14933
15054
|
return this.positions.get(jsonPath);
|
|
14934
15055
|
}
|
|
15056
|
+
/**
|
|
15057
|
+
* Get the position for a given $ref path
|
|
15058
|
+
* @param refPath - The $ref path (e.g., "./schemas/User.yaml#/User")
|
|
15059
|
+
*/
|
|
15060
|
+
getRef(refPath) {
|
|
15061
|
+
return this.refTargets.get(refPath);
|
|
15062
|
+
}
|
|
14935
15063
|
/**
|
|
14936
15064
|
* Set the position for a given JSON path
|
|
14937
15065
|
*/
|
|
@@ -14950,10 +15078,71 @@ class SourcePositionMap {
|
|
|
14950
15078
|
keys() {
|
|
14951
15079
|
return this.positions.keys();
|
|
14952
15080
|
}
|
|
15081
|
+
/**
|
|
15082
|
+
* Get all entries as [jsonPath, position] pairs
|
|
15083
|
+
*/
|
|
15084
|
+
entries() {
|
|
15085
|
+
return this.positions.entries();
|
|
15086
|
+
}
|
|
15087
|
+
/**
|
|
15088
|
+
* Get the number of files tracked in this map
|
|
15089
|
+
*/
|
|
15090
|
+
get fileCount() {
|
|
15091
|
+
return this.fileUrls.size;
|
|
15092
|
+
}
|
|
15093
|
+
/**
|
|
15094
|
+
* Track a $ref target value and its position
|
|
15095
|
+
*/
|
|
15096
|
+
setRefTarget(refValue, position) {
|
|
15097
|
+
this.refTargets.set(refValue, position);
|
|
15098
|
+
}
|
|
15099
|
+
/**
|
|
15100
|
+
* Find the position of a $ref that targets a file containing the given path,
|
|
15101
|
+
* or an internal ref containing the given token.
|
|
15102
|
+
*/
|
|
15103
|
+
findRefPosition(targetPath, token) {
|
|
15104
|
+
const targetFileName = targetPath.split("/").pop() || targetPath;
|
|
15105
|
+
for (const [refValue, position] of this.refTargets) {
|
|
15106
|
+
if (refValue.includes(targetFileName)) {
|
|
15107
|
+
return { position, refValue };
|
|
15108
|
+
}
|
|
15109
|
+
if (token && refValue.startsWith("#/") && refValue.includes(token)) {
|
|
15110
|
+
return { position, refValue };
|
|
15111
|
+
}
|
|
15112
|
+
}
|
|
15113
|
+
}
|
|
15114
|
+
/**
|
|
15115
|
+
* Merge positions from another map, setting filePath on each position.
|
|
15116
|
+
* Used to aggregate positions from multiple files (e.g., external $refs).
|
|
15117
|
+
* @param other - The source position map to merge from
|
|
15118
|
+
* @param fileUrl - The file URL to associate with these positions
|
|
15119
|
+
*/
|
|
15120
|
+
merge(other, fileUrl) {
|
|
15121
|
+
const filePath = extractFilePath(fileUrl);
|
|
15122
|
+
this.fileUrls.add(fileUrl);
|
|
15123
|
+
for (const [jsonPath, position] of other.entries()) {
|
|
15124
|
+
this.positions.set(jsonPath, {
|
|
15125
|
+
...position,
|
|
15126
|
+
filePath
|
|
15127
|
+
});
|
|
15128
|
+
}
|
|
15129
|
+
for (const [refValue, position] of other.refTargets) {
|
|
15130
|
+
this.refTargets.set(refValue, { ...position, filePath });
|
|
15131
|
+
}
|
|
15132
|
+
}
|
|
15133
|
+
}
|
|
15134
|
+
function extractFilePath(fileUrl) {
|
|
15135
|
+
try {
|
|
15136
|
+
const url2 = new URL(fileUrl);
|
|
15137
|
+
return url2.pathname;
|
|
15138
|
+
} catch {
|
|
15139
|
+
return fileUrl;
|
|
15140
|
+
}
|
|
14953
15141
|
}
|
|
14954
|
-
function buildSourcePositionMap(yamlContent) {
|
|
15142
|
+
function buildSourcePositionMap(yamlContent, fileUrl) {
|
|
14955
15143
|
const positionMap = new SourcePositionMap();
|
|
14956
15144
|
const lineCounter = new LineCounter();
|
|
15145
|
+
const filePath = extractFilePath(fileUrl);
|
|
14957
15146
|
const doc = parseDocument(yamlContent, { lineCounter });
|
|
14958
15147
|
if (!doc.contents || !isMap(doc.contents)) {
|
|
14959
15148
|
return positionMap;
|
|
@@ -14965,7 +15154,15 @@ function buildSourcePositionMap(yamlContent) {
|
|
|
14965
15154
|
const range = pair.key.range;
|
|
14966
15155
|
if (range) {
|
|
14967
15156
|
const pos = lineCounter.linePos(range[0]);
|
|
14968
|
-
positionMap.set(jsonPath, { line: pos.line, column: pos.col - 1 });
|
|
15157
|
+
positionMap.set(jsonPath, { line: pos.line, column: pos.col - 1, filePath });
|
|
15158
|
+
if (pair.key.value === "$ref" && pair.value && isScalar(pair.value)) {
|
|
15159
|
+
const refValue = String(pair.value.value);
|
|
15160
|
+
positionMap.setRefTarget(refValue, {
|
|
15161
|
+
line: pos.line,
|
|
15162
|
+
column: pos.col - 1,
|
|
15163
|
+
filePath
|
|
15164
|
+
});
|
|
15165
|
+
}
|
|
14969
15166
|
}
|
|
14970
15167
|
}
|
|
14971
15168
|
}
|
|
@@ -14988,6 +15185,9 @@ function buildJsonPath(pair, path2) {
|
|
|
14988
15185
|
if (segments.length >= 3 && segments[0] === "components" && segments[1] === "schemas") {
|
|
14989
15186
|
return segments.join("/");
|
|
14990
15187
|
}
|
|
15188
|
+
if (segments.length >= 1 && !["openapi", "info", "servers", "paths", "components", "x-onestore"].includes(segments[0])) {
|
|
15189
|
+
return segments.join("/");
|
|
15190
|
+
}
|
|
14991
15191
|
return void 0;
|
|
14992
15192
|
}
|
|
14993
15193
|
const positionMapCache = /* @__PURE__ */ new Map();
|
|
@@ -14996,7 +15196,7 @@ const positionTrackingParser = {
|
|
|
14996
15196
|
canParse: [".yaml", ".yml"],
|
|
14997
15197
|
async parse(file) {
|
|
14998
15198
|
const content = Buffer.isBuffer(file.data) ? file.data.toString() : file.data;
|
|
14999
|
-
const positionMap = buildSourcePositionMap(content);
|
|
15199
|
+
const positionMap = buildSourcePositionMap(content, file.url);
|
|
15000
15200
|
positionMapCache.set(file.url, positionMap);
|
|
15001
15201
|
return parse(content);
|
|
15002
15202
|
}
|
|
@@ -15012,12 +15212,25 @@ const PARSER_OPTIONS = {
|
|
|
15012
15212
|
// Still validate $ref resolution
|
|
15013
15213
|
}
|
|
15014
15214
|
};
|
|
15215
|
+
function findRefPositionInCache(targetPath, token) {
|
|
15216
|
+
for (const positionMap of positionMapCache.values()) {
|
|
15217
|
+
const result = positionMap.findRefPosition(targetPath, token);
|
|
15218
|
+
if (result) {
|
|
15219
|
+
return result;
|
|
15220
|
+
}
|
|
15221
|
+
}
|
|
15222
|
+
}
|
|
15015
15223
|
async function parseSwaggerDocument(source, logger) {
|
|
15016
15224
|
const sourceUrl = source.toString();
|
|
15017
15225
|
try {
|
|
15018
|
-
const
|
|
15019
|
-
const
|
|
15020
|
-
|
|
15226
|
+
const parser = new SwaggerParser();
|
|
15227
|
+
const api = await parser.parse(sourceUrl, PARSER_OPTIONS);
|
|
15228
|
+
const $refs = await parser.resolve(sourceUrl, PARSER_OPTIONS);
|
|
15229
|
+
const positionMap = new SourcePositionMap();
|
|
15230
|
+
for (const [fileUrl, filePositionMap] of positionMapCache) {
|
|
15231
|
+
positionMap.merge(filePositionMap, fileUrl);
|
|
15232
|
+
}
|
|
15233
|
+
positionMapCache.clear();
|
|
15021
15234
|
if (!("openapi" in api) || !api.openapi.startsWith("3.")) {
|
|
15022
15235
|
throw new Error(
|
|
15023
15236
|
`Only OpenAPI 3.x documents are supported. Found version: ${api.openapi || api.swagger || "unknown"}`
|
|
@@ -15025,10 +15238,50 @@ async function parseSwaggerDocument(source, logger) {
|
|
|
15025
15238
|
}
|
|
15026
15239
|
return {
|
|
15027
15240
|
document: api,
|
|
15028
|
-
positionMap
|
|
15241
|
+
positionMap,
|
|
15242
|
+
$refs
|
|
15029
15243
|
};
|
|
15030
15244
|
} catch (error) {
|
|
15031
|
-
|
|
15245
|
+
if (error instanceof MissingPointerError) {
|
|
15246
|
+
const missingFile = error.source;
|
|
15247
|
+
const tokenMatch = error.message.match(/Token "([^"]+)"/);
|
|
15248
|
+
const token = (tokenMatch == null ? void 0 : tokenMatch[1]) ?? "unknown";
|
|
15249
|
+
const refInfo = findRefPositionInCache(missingFile, token);
|
|
15250
|
+
const filename = missingFile.split("/").pop() ?? missingFile;
|
|
15251
|
+
if (refInfo) {
|
|
15252
|
+
const { position, refValue } = refInfo;
|
|
15253
|
+
logger.error(
|
|
15254
|
+
position,
|
|
15255
|
+
`Cannot resolve reference '${refValue}': token '${token}' does not exist in '${filename}'`
|
|
15256
|
+
);
|
|
15257
|
+
} else {
|
|
15258
|
+
logger.error(
|
|
15259
|
+
{ line: 0, column: 0 },
|
|
15260
|
+
`Cannot resolve reference: token '${token}' does not exist in '${filename}'`
|
|
15261
|
+
);
|
|
15262
|
+
}
|
|
15263
|
+
positionMapCache.clear();
|
|
15264
|
+
throw error;
|
|
15265
|
+
}
|
|
15266
|
+
if (error instanceof ResolverError) {
|
|
15267
|
+
const missingFile = error.source;
|
|
15268
|
+
const refInfo = findRefPositionInCache(missingFile);
|
|
15269
|
+
if (refInfo) {
|
|
15270
|
+
const { position, refValue } = refInfo;
|
|
15271
|
+
logger.error(
|
|
15272
|
+
position,
|
|
15273
|
+
`Cannot resolve external reference '${refValue}': file not found '${missingFile}'`
|
|
15274
|
+
);
|
|
15275
|
+
} else {
|
|
15276
|
+
logger.error(
|
|
15277
|
+
{ line: 0, column: 0 },
|
|
15278
|
+
`Cannot resolve reference '${missingFile}': file not found`
|
|
15279
|
+
);
|
|
15280
|
+
}
|
|
15281
|
+
positionMapCache.clear();
|
|
15282
|
+
throw error;
|
|
15283
|
+
}
|
|
15284
|
+
positionMapCache.clear();
|
|
15032
15285
|
const message = error instanceof Error ? error.message : String(error);
|
|
15033
15286
|
logger.error(
|
|
15034
15287
|
{ line: 0, column: 0 },
|
|
@@ -15038,8 +15291,8 @@ async function parseSwaggerDocument(source, logger) {
|
|
|
15038
15291
|
}
|
|
15039
15292
|
}
|
|
15040
15293
|
async function parseUrl(source, services, fileParserLogger) {
|
|
15041
|
-
const { document, positionMap } = await parseSwaggerDocument(source, fileParserLogger);
|
|
15042
|
-
const api = new SwaggerAPI(document, source, services, fileParserLogger, positionMap);
|
|
15294
|
+
const { document, positionMap, $refs } = await parseSwaggerDocument(source, fileParserLogger);
|
|
15295
|
+
const api = new SwaggerAPI(document, source, services, fileParserLogger, positionMap, $refs);
|
|
15043
15296
|
api.validate();
|
|
15044
15297
|
return api;
|
|
15045
15298
|
}
|