@postman-cse/onboarding-bootstrap 1.1.0 → 1.2.1
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 +205 -443
- package/action.yml +2 -2
- package/dist/action.cjs +308 -49
- package/dist/cli.cjs +308 -49
- package/dist/index.cjs +308 -49
- package/package.json +2 -1
package/action.yml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
name:
|
|
2
|
-
description:
|
|
1
|
+
name: Postman Workspace Bootstrap
|
|
2
|
+
description: Provision a Postman workspace from an OpenAPI spec and generate baseline, smoke, and contract collections in one step.
|
|
3
3
|
author: Postman
|
|
4
4
|
branding:
|
|
5
5
|
icon: box
|
package/dist/action.cjs
CHANGED
|
@@ -49788,6 +49788,38 @@ function normalizeSchema(ctx, schema2, options) {
|
|
|
49788
49788
|
const sourceSchema = { ...record };
|
|
49789
49789
|
const nullable = sourceSchema.nullable === true && ctx.version === "3.0";
|
|
49790
49790
|
delete sourceSchema.nullable;
|
|
49791
|
+
const discriminator = asRecord3(sourceSchema.discriminator);
|
|
49792
|
+
if (discriminator && typeof discriminator.propertyName === "string" && discriminator.propertyName) {
|
|
49793
|
+
const propertyName = discriminator.propertyName;
|
|
49794
|
+
const branchKey = Array.isArray(sourceSchema.oneOf) ? "oneOf" : Array.isArray(sourceSchema.anyOf) ? "anyOf" : "";
|
|
49795
|
+
const members = branchKey ? sourceSchema[branchKey] : [];
|
|
49796
|
+
const memberRefs = members.map((member) => {
|
|
49797
|
+
const memberRecord = asRecord3(member);
|
|
49798
|
+
const memberRef = memberRecord && Object.keys(memberRecord).length === 1 && typeof memberRecord.$ref === "string" ? memberRecord.$ref : "";
|
|
49799
|
+
return memberRef.startsWith("#/") ? memberRef : "";
|
|
49800
|
+
});
|
|
49801
|
+
if (branchKey && members.length > 0 && memberRefs.every(Boolean)) {
|
|
49802
|
+
const valuesByRef = /* @__PURE__ */ new Map();
|
|
49803
|
+
const refByMappingKey = /* @__PURE__ */ new Map();
|
|
49804
|
+
for (const [value, target] of Object.entries(asRecord3(discriminator.mapping) ?? {})) {
|
|
49805
|
+
if (typeof target !== "string" || !target) continue;
|
|
49806
|
+
const targetRef = target.startsWith("#/") ? target : `#/components/schemas/${target}`;
|
|
49807
|
+
valuesByRef.set(targetRef, [...valuesByRef.get(targetRef) ?? [], value]);
|
|
49808
|
+
refByMappingKey.set(value, targetRef);
|
|
49809
|
+
}
|
|
49810
|
+
sourceSchema[branchKey] = members.map((member, index) => {
|
|
49811
|
+
const memberRef = memberRefs[index] ?? "";
|
|
49812
|
+
const tail = (memberRef.split("/").pop() ?? "").replace(/~1/g, "/").replace(/~0/g, "~");
|
|
49813
|
+
const values = [...valuesByRef.get(memberRef) ?? []];
|
|
49814
|
+
const tailClaimedElsewhere = refByMappingKey.has(tail) && refByMappingKey.get(tail) !== memberRef;
|
|
49815
|
+
if (tail && !tailClaimedElsewhere && !values.includes(tail)) values.push(tail);
|
|
49816
|
+
const dispatch = values.length === 1 ? { const: values[0] } : { enum: values };
|
|
49817
|
+
return { allOf: [member, { type: "object", required: [propertyName], properties: { [propertyName]: dispatch } }] };
|
|
49818
|
+
});
|
|
49819
|
+
} else {
|
|
49820
|
+
ctx.notes.add("discriminator");
|
|
49821
|
+
}
|
|
49822
|
+
}
|
|
49791
49823
|
const directionStrippedFlag = ctx.direction === "request" ? "readOnly" : "writeOnly";
|
|
49792
49824
|
const strippedProperties = /* @__PURE__ */ new Set();
|
|
49793
49825
|
const rawProperties = asRecord3(sourceSchema.properties);
|
|
@@ -49960,7 +49992,7 @@ function packSchema(root, schema2, version, direction = "response") {
|
|
|
49960
49992
|
if (schema2 === true) return { schema: { $schema: rootDialect(root, version) } };
|
|
49961
49993
|
if (schema2 === false) return unsupported("Boolean false JSON Schema rejects every instance and is unsupported");
|
|
49962
49994
|
const dialect = rootDialect(root, version, asRecord3(schema2) ?? void 0);
|
|
49963
|
-
const ctx = { root, version, direction, dialect, defs: /* @__PURE__ */ new Map() };
|
|
49995
|
+
const ctx = { root, version, direction, dialect, defs: /* @__PURE__ */ new Map(), notes: /* @__PURE__ */ new Set() };
|
|
49964
49996
|
const normalized = normalizeSchema(ctx, schema2, { depth: 0, rootSchema: true });
|
|
49965
49997
|
const message = hasUnsupported(normalized);
|
|
49966
49998
|
if (message) return unsupported(message);
|
|
@@ -49985,7 +50017,9 @@ function packSchema(root, schema2, version, direction = "response") {
|
|
|
49985
50017
|
if (!normalizedRecord) return unsupported("Referenced schemas require an object root schema");
|
|
49986
50018
|
normalizedRecord.$defs = Object.fromEntries([...ctx.defs.values()].map((entry) => [entry.name, entry.schema]));
|
|
49987
50019
|
}
|
|
49988
|
-
|
|
50020
|
+
const packed = { schema: normalized };
|
|
50021
|
+
if (ctx.notes.size > 0) packed.notes = [...ctx.notes].sort();
|
|
50022
|
+
return packed;
|
|
49989
50023
|
} catch (error2) {
|
|
49990
50024
|
return unsupported(error2 instanceof Error ? error2.message : String(error2));
|
|
49991
50025
|
}
|
|
@@ -50158,6 +50192,7 @@ function securityCheckFor(schemeName, scheme) {
|
|
|
50158
50192
|
const httpScheme = String(scheme.scheme || "").toLowerCase();
|
|
50159
50193
|
if (httpScheme === "basic") return { scheme: schemeName, kind, checkable: true, prefix: "Basic " };
|
|
50160
50194
|
if (httpScheme === "bearer") return { scheme: schemeName, kind, checkable: true, prefix: "Bearer " };
|
|
50195
|
+
if (httpScheme) return { scheme: schemeName, kind, checkable: true, prefix: `${httpScheme.charAt(0).toUpperCase()}${httpScheme.slice(1)} ` };
|
|
50161
50196
|
return { scheme: schemeName, kind, checkable: true, in: "header", name: "Authorization" };
|
|
50162
50197
|
}
|
|
50163
50198
|
if (scheme?.type === "oauth2" || scheme?.type === "openIdConnect") {
|
|
@@ -50191,7 +50226,18 @@ var IGNORED_HEADER_PARAMS = /* @__PURE__ */ new Set(["accept", "content-type", "
|
|
|
50191
50226
|
function isIgnoredParameter(location2, name) {
|
|
50192
50227
|
return location2 === "header" && IGNORED_HEADER_PARAMS.has(name.toLowerCase());
|
|
50193
50228
|
}
|
|
50194
|
-
function
|
|
50229
|
+
function jsonContentParameterMedia(param) {
|
|
50230
|
+
const content = asRecord4(param.content);
|
|
50231
|
+
if (!content) return void 0;
|
|
50232
|
+
const entries = Object.entries(content);
|
|
50233
|
+
if (entries.length !== 1) return void 0;
|
|
50234
|
+
const [contentType, mediaObject] = entries[0];
|
|
50235
|
+
const base = contentType.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
50236
|
+
if (!isJsonBaseType(base)) return void 0;
|
|
50237
|
+
const schema2 = asRecord4(mediaObject)?.schema;
|
|
50238
|
+
return schema2 === void 0 ? void 0 : schema2;
|
|
50239
|
+
}
|
|
50240
|
+
function collectSerializationWarnings(root, pathItem, operation, decodedKeys) {
|
|
50195
50241
|
const warnings = [];
|
|
50196
50242
|
for (const param of resolvedParameters(root, pathItem, operation)) {
|
|
50197
50243
|
const location2 = String(param.in || "").toLowerCase();
|
|
@@ -50201,7 +50247,9 @@ function collectSerializationWarnings(root, pathItem, operation) {
|
|
|
50201
50247
|
const style = typeof param.style === "string" ? param.style : defaultStyle;
|
|
50202
50248
|
const defaultExplode = style === "form";
|
|
50203
50249
|
const explode = typeof param.explode === "boolean" ? param.explode : defaultExplode;
|
|
50204
|
-
|
|
50250
|
+
const unvalidatedContent = param.content !== void 0 && (jsonContentParameterMedia(param) === void 0 || location2 !== "query" && location2 !== "header");
|
|
50251
|
+
if (style !== defaultStyle || explode !== defaultExplode || param.allowReserved === true || unvalidatedContent) {
|
|
50252
|
+
if (decodedKeys.has(`${location2}:${name.toLowerCase()}`) && param.allowReserved !== true && param.content === void 0) continue;
|
|
50205
50253
|
warnings.push(`CONTRACT_PARAM_SERIALIZATION_NOT_VALIDATED: parameter ${location2}:${name} declares non-default style, explode, allowReserved, or content and its serialization is not validated`);
|
|
50206
50254
|
}
|
|
50207
50255
|
}
|
|
@@ -50216,7 +50264,27 @@ function packedScalarSchema(packed) {
|
|
|
50216
50264
|
if (!types2.every((entry) => typeof entry === "string" && SCALAR_SCHEMA_TYPES.has(entry))) return void 0;
|
|
50217
50265
|
return packed.schema;
|
|
50218
50266
|
}
|
|
50219
|
-
function
|
|
50267
|
+
function packedArrayItemsSchema(packed) {
|
|
50268
|
+
if (packed.unsupported || packed.schema === void 0) return void 0;
|
|
50269
|
+
const record = asRecord4(packed.schema);
|
|
50270
|
+
if (!record) return void 0;
|
|
50271
|
+
const types2 = Array.isArray(record.type) ? record.type : [record.type];
|
|
50272
|
+
if (types2.length !== 1 || types2[0] !== "array") return void 0;
|
|
50273
|
+
if (record.prefixItems !== void 0 || Array.isArray(record.items)) return void 0;
|
|
50274
|
+
if (record.items === void 0) return {};
|
|
50275
|
+
const items = asRecord4(record.items);
|
|
50276
|
+
if (!items || typeof items.$ref === "string") return void 0;
|
|
50277
|
+
const itemTypes = Array.isArray(items.type) ? items.type : [items.type];
|
|
50278
|
+
if (!itemTypes.every((entry) => typeof entry === "string" && SCALAR_SCHEMA_TYPES.has(entry))) return void 0;
|
|
50279
|
+
return items;
|
|
50280
|
+
}
|
|
50281
|
+
var QUERY_ARRAY_DECODES = {
|
|
50282
|
+
"form:true": "multi",
|
|
50283
|
+
"form:false": "csv",
|
|
50284
|
+
"spaceDelimited:false": "ssv",
|
|
50285
|
+
"pipeDelimited:false": "pipes"
|
|
50286
|
+
};
|
|
50287
|
+
function collectParameterChecks(root, pathItem, operation, version, operationId, pathTemplate, warnings) {
|
|
50220
50288
|
const securityKeys = collectSecurityApiKeys(root, operation);
|
|
50221
50289
|
const checks = [];
|
|
50222
50290
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -50229,32 +50297,65 @@ function collectParameterChecks(root, pathItem, operation, version, operationId,
|
|
|
50229
50297
|
}).filter((param) => Boolean(param));
|
|
50230
50298
|
for (const param of orderedParams) {
|
|
50231
50299
|
const location2 = String(param.in || "").toLowerCase();
|
|
50232
|
-
if (location2 !== "query" && location2 !== "header") continue;
|
|
50300
|
+
if (location2 !== "query" && location2 !== "header" && location2 !== "path" && location2 !== "cookie") continue;
|
|
50233
50301
|
const name = String(param.name || "");
|
|
50234
50302
|
if (!name || isIgnoredParameter(location2, name)) continue;
|
|
50235
50303
|
const key = `${location2}:${name.toLowerCase()}`;
|
|
50236
50304
|
if (seen.has(key)) continue;
|
|
50237
50305
|
seen.add(key);
|
|
50238
50306
|
if (securityKeys.has(key)) continue;
|
|
50307
|
+
const contentMedia = jsonContentParameterMedia(param);
|
|
50308
|
+
if (contentMedia !== void 0 && (location2 === "query" || location2 === "header")) {
|
|
50309
|
+
const packed2 = packSchema(root, contentMedia, version, "request");
|
|
50310
|
+
warnings.push(...packNoteWarnings(packed2, `parameter ${location2}:${name} of ${operationId}`));
|
|
50311
|
+
if (packed2.unsupported) {
|
|
50312
|
+
warnings.push(`CONTRACT_SCHEMA_NOT_COMPILED: parameter ${location2}:${name} schema on ${operationId} skipped (${packed2.unsupported})`);
|
|
50313
|
+
} else if (packed2.schema !== void 0) {
|
|
50314
|
+
const check2 = { in: location2, name, required: param.required === true, content: true, schema: packed2.schema };
|
|
50315
|
+
if (location2 === "query" && param.allowEmptyValue === true) check2.allowEmptyValue = true;
|
|
50316
|
+
checks.push(check2);
|
|
50317
|
+
}
|
|
50318
|
+
continue;
|
|
50319
|
+
}
|
|
50239
50320
|
if (param.content !== void 0 || param.schema === void 0) continue;
|
|
50240
50321
|
const defaultStyle = DEFAULT_PARAM_STYLES[location2];
|
|
50241
50322
|
const style = typeof param.style === "string" ? param.style : defaultStyle;
|
|
50242
50323
|
const defaultExplode = style === "form";
|
|
50243
50324
|
const explode = typeof param.explode === "boolean" ? param.explode : defaultExplode;
|
|
50244
|
-
|
|
50325
|
+
const defaultSerialization = style === defaultStyle && explode === defaultExplode;
|
|
50245
50326
|
const packed = packSchema(root, param.schema, version);
|
|
50327
|
+
const noteWarnings = packNoteWarnings(packed, `parameter ${location2}:${name} of ${operationId}`);
|
|
50328
|
+
if (defaultSerialization) warnings.push(...noteWarnings);
|
|
50246
50329
|
if (packed.unsupported) {
|
|
50247
|
-
warnings.push(`CONTRACT_SCHEMA_NOT_COMPILED: parameter ${location2}:${name} schema on ${operationId} skipped (${packed.unsupported})`);
|
|
50330
|
+
if (defaultSerialization) warnings.push(`CONTRACT_SCHEMA_NOT_COMPILED: parameter ${location2}:${name} schema on ${operationId} skipped (${packed.unsupported})`);
|
|
50248
50331
|
continue;
|
|
50249
50332
|
}
|
|
50250
|
-
|
|
50251
|
-
|
|
50252
|
-
|
|
50333
|
+
if (location2 === "path" && !pathTemplate.split("/").includes(`{${name}}`)) continue;
|
|
50334
|
+
const scalarSchema = packedScalarSchema(packed);
|
|
50335
|
+
if (scalarSchema !== void 0) {
|
|
50336
|
+
if (!defaultSerialization) continue;
|
|
50337
|
+
const check2 = { in: location2, name, required: param.required === true, schema: scalarSchema };
|
|
50338
|
+
if (location2 === "query" && param.allowEmptyValue === true) check2.allowEmptyValue = true;
|
|
50339
|
+
checks.push(check2);
|
|
50340
|
+
continue;
|
|
50341
|
+
}
|
|
50342
|
+
if (location2 !== "query" && location2 !== "header") continue;
|
|
50343
|
+
const items = packedArrayItemsSchema(packed);
|
|
50344
|
+
if (items === void 0) continue;
|
|
50345
|
+
const decode = location2 === "query" ? QUERY_ARRAY_DECODES[`${style}:${explode}`] : style === "simple" && !explode ? "csv" : void 0;
|
|
50346
|
+
if (!decode) continue;
|
|
50347
|
+
if (!defaultSerialization) warnings.push(...noteWarnings);
|
|
50348
|
+
const check = { in: location2, name, required: param.required === true, schema: packed.schema, decode, items };
|
|
50253
50349
|
if (location2 === "query" && param.allowEmptyValue === true) check.allowEmptyValue = true;
|
|
50254
50350
|
checks.push(check);
|
|
50255
50351
|
}
|
|
50256
50352
|
return checks.length > 0 ? checks : void 0;
|
|
50257
50353
|
}
|
|
50354
|
+
function packNoteWarnings(packed, context) {
|
|
50355
|
+
return (packed.notes ?? []).map(
|
|
50356
|
+
(note) => note === "discriminator" ? `CONTRACT_DISCRIMINATOR_NOT_VALIDATED: discriminator on ${context} has no sibling oneOf/anyOf of internal $ref members and is not validated` : `CONTRACT_SCHEMA_NOT_COMPILED: ${note} on ${context} is not validated`
|
|
50357
|
+
);
|
|
50358
|
+
}
|
|
50258
50359
|
function collectDeclaredQueryParameters(root, pathItem, operation) {
|
|
50259
50360
|
const names = /* @__PURE__ */ new Set();
|
|
50260
50361
|
for (const param of resolvedParameters(root, pathItem, operation)) {
|
|
@@ -50332,7 +50433,10 @@ function propertyIsBinary(root, properties, name) {
|
|
|
50332
50433
|
}
|
|
50333
50434
|
if (!schema2) return false;
|
|
50334
50435
|
if (schema2.format === "binary") return true;
|
|
50335
|
-
|
|
50436
|
+
if (typeof schema2.contentMediaType !== "string" || typeof schema2.contentEncoding === "string") return false;
|
|
50437
|
+
const media = schema2.contentMediaType.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
50438
|
+
if (!media) return false;
|
|
50439
|
+
return media !== "application/json" && !media.endsWith("+json") && !media.startsWith("text/");
|
|
50336
50440
|
}
|
|
50337
50441
|
function fieldEncodings(root, base, mediaObject, properties) {
|
|
50338
50442
|
const declared = asRecord4(mediaObject?.encoding);
|
|
@@ -50350,6 +50454,9 @@ function fieldEncodings(root, base, mediaObject, properties) {
|
|
|
50350
50454
|
if (typeof encoding.contentType === "string" && encoding.contentType.trim()) {
|
|
50351
50455
|
entry.contentType = encoding.contentType.toLowerCase();
|
|
50352
50456
|
}
|
|
50457
|
+
if (base === "multipart/form-data" && asRecord4(encoding.headers)) {
|
|
50458
|
+
entry.hasHeaders = true;
|
|
50459
|
+
}
|
|
50353
50460
|
if (base === "application/x-www-form-urlencoded") {
|
|
50354
50461
|
const style = typeof encoding.style === "string" ? encoding.style : "form";
|
|
50355
50462
|
const explode = typeof encoding.explode === "boolean" ? encoding.explode : style === "form";
|
|
@@ -50362,7 +50469,22 @@ function fieldEncodings(root, base, mediaObject, properties) {
|
|
|
50362
50469
|
}
|
|
50363
50470
|
return Object.keys(encodings).length > 0 ? encodings : void 0;
|
|
50364
50471
|
}
|
|
50365
|
-
function
|
|
50472
|
+
function formFieldSchemas(root, version, properties, context, warnings) {
|
|
50473
|
+
const schemas = {};
|
|
50474
|
+
for (const name of Object.keys(properties)) {
|
|
50475
|
+
const packed = packSchema(root, properties[name], version, "request");
|
|
50476
|
+
warnings.push(...packNoteWarnings(packed, `field ${name} of ${context}`));
|
|
50477
|
+
if (packed.unsupported) {
|
|
50478
|
+
warnings.push(`CONTRACT_SCHEMA_NOT_COMPILED: field ${name} of ${context} skipped (${packed.unsupported})`);
|
|
50479
|
+
continue;
|
|
50480
|
+
}
|
|
50481
|
+
if (packed.schema === void 0) continue;
|
|
50482
|
+
const schema2 = packedScalarSchema(packed);
|
|
50483
|
+
if (schema2 !== void 0) schemas[name] = schema2;
|
|
50484
|
+
}
|
|
50485
|
+
return Object.keys(schemas).length > 0 ? schemas : void 0;
|
|
50486
|
+
}
|
|
50487
|
+
function requestBodyFieldRules(root, content, version, operationId, warnings) {
|
|
50366
50488
|
const rules = {};
|
|
50367
50489
|
for (const [contentType, mediaObject] of Object.entries(content)) {
|
|
50368
50490
|
const base = contentType.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
@@ -50372,10 +50494,13 @@ function requestBodyFieldRules(root, content) {
|
|
|
50372
50494
|
if (!merged) continue;
|
|
50373
50495
|
const readOnly = Object.keys(merged.properties).filter((name) => propertyIsReadOnly(root, merged.properties, name));
|
|
50374
50496
|
const required = merged.required.filter((name) => !propertyIsReadOnly(root, merged.properties, name));
|
|
50375
|
-
const
|
|
50376
|
-
|
|
50497
|
+
const formRules = BODY_FIELD_RULE_TYPES.has(base);
|
|
50498
|
+
const encodings = formRules ? fieldEncodings(root, base, mediaRecord, merged.properties) : void 0;
|
|
50499
|
+
const fieldSchemas = formRules ? formFieldSchemas(root, version, merged.properties, `request body ${contentType} of ${operationId}`, warnings) : void 0;
|
|
50500
|
+
if (required.length > 0 || readOnly.length > 0 || encodings || fieldSchemas) {
|
|
50377
50501
|
const rule = { required, readOnly };
|
|
50378
50502
|
if (encodings) rule.encodings = encodings;
|
|
50503
|
+
if (fieldSchemas) rule.fieldSchemas = fieldSchemas;
|
|
50379
50504
|
rules[base] = rule;
|
|
50380
50505
|
}
|
|
50381
50506
|
}
|
|
@@ -50396,6 +50521,7 @@ function requestBodyJsonSchemas(root, content, version, operationId, warnings) {
|
|
|
50396
50521
|
}
|
|
50397
50522
|
if (schema2 === void 0) continue;
|
|
50398
50523
|
const packed = packSchema(root, schema2, version, "request");
|
|
50524
|
+
warnings.push(...packNoteWarnings(packed, `request body ${contentType} of ${operationId}`));
|
|
50399
50525
|
if (mediaRecord) validateExamples(root, mediaRecord, packed, contentType, operationId, exampleWarnings);
|
|
50400
50526
|
if (packed.unsupported) {
|
|
50401
50527
|
warnings.push(`CONTRACT_REQUEST_SCHEMA_NOT_VALIDATED: request body schema for ${contentType} on ${operationId} is not validated (${packed.unsupported})`);
|
|
@@ -50410,7 +50536,7 @@ function collectRequestBody(root, operation, version, operationId, warnings) {
|
|
|
50410
50536
|
const body = resolveInternalRef(root, operation.requestBody);
|
|
50411
50537
|
if (!body) return void 0;
|
|
50412
50538
|
const content = asRecord4(body.content);
|
|
50413
|
-
const fieldRules = content ? requestBodyFieldRules(root, content) : void 0;
|
|
50539
|
+
const fieldRules = content ? requestBodyFieldRules(root, content, version, operationId, warnings) : void 0;
|
|
50414
50540
|
if (fieldRules) {
|
|
50415
50541
|
for (const [base, rule] of Object.entries(fieldRules)) {
|
|
50416
50542
|
for (const [field, encoding] of Object.entries(rule.encodings ?? {})) {
|
|
@@ -50419,6 +50545,11 @@ function collectRequestBody(root, operation, version, operationId, warnings) {
|
|
|
50419
50545
|
`CONTRACT_PARAM_SERIALIZATION_NOT_VALIDATED: ${base} request body field ${field} on ${operationId} declares non-default encoding style, explode, or allowReserved and its serialization is not validated`
|
|
50420
50546
|
);
|
|
50421
50547
|
}
|
|
50548
|
+
if (encoding.hasHeaders) {
|
|
50549
|
+
warnings.push(
|
|
50550
|
+
`CONTRACT_ENCODING_HEADERS_NOT_VALIDATED: ${base} request body field ${field} on ${operationId} declares per-part headers that generated formdata entries cannot carry`
|
|
50551
|
+
);
|
|
50552
|
+
}
|
|
50422
50553
|
}
|
|
50423
50554
|
}
|
|
50424
50555
|
}
|
|
@@ -50466,6 +50597,7 @@ function responseContent(root, version, response, context, warnings) {
|
|
|
50466
50597
|
const mediaRecord = asRecord4(mediaObject);
|
|
50467
50598
|
const schema2 = mediaRecord?.schema;
|
|
50468
50599
|
let packed = schema2 === void 0 ? {} : packSchema(root, schema2, version);
|
|
50600
|
+
for (const warning2 of packNoteWarnings(packed, `response ${contentType} of ${context}`)) warnings.add(warning2);
|
|
50469
50601
|
if (isSchemaGraphOverflow(packed)) {
|
|
50470
50602
|
warnings.add(`CONTRACT_SCHEMA_NOT_COMPILED: response schema for ${contentType} on ${context} skipped (${packed.unsupported})`);
|
|
50471
50603
|
packed = {};
|
|
@@ -50497,12 +50629,18 @@ function responseHeaders(root, version, response, context, warnings) {
|
|
|
50497
50629
|
continue;
|
|
50498
50630
|
}
|
|
50499
50631
|
const packed = packSchema(root, header.schema, version);
|
|
50632
|
+
for (const warning2 of packNoteWarnings(packed, `response header ${name} of ${context}`)) warnings.add(warning2);
|
|
50500
50633
|
if (isSchemaGraphOverflow(packed)) {
|
|
50501
50634
|
warnings.add(`CONTRACT_SCHEMA_NOT_COMPILED: response header ${name} schema on ${context} skipped (${packed.unsupported})`);
|
|
50502
50635
|
entries.push({ name, required });
|
|
50503
50636
|
continue;
|
|
50504
50637
|
}
|
|
50505
50638
|
if (!packed.unsupported && packed.schema !== void 0 && packedScalarSchema(packed) === void 0) {
|
|
50639
|
+
const items = packedArrayItemsSchema(packed);
|
|
50640
|
+
if (items !== void 0) {
|
|
50641
|
+
entries.push({ name, required, schema: packed.schema, items });
|
|
50642
|
+
continue;
|
|
50643
|
+
}
|
|
50506
50644
|
warnings.add(`CONTRACT_HEADER_SCHEMA_NOT_VALIDATED: response header ${name} on ${context} declares a non-scalar schema and its value is not validated`);
|
|
50507
50645
|
entries.push({ name, required });
|
|
50508
50646
|
continue;
|
|
@@ -50561,10 +50699,14 @@ function buildContractIndex(root) {
|
|
|
50561
50699
|
path8,
|
|
50562
50700
|
...operationServers(root, pathItem, operation).map((server) => joinPaths(serverPathPrefix(server), path8))
|
|
50563
50701
|
].map(normalizePath))];
|
|
50702
|
+
const operationId = `${lowerMethod.toUpperCase()} ${path8}`;
|
|
50564
50703
|
const opWarnings = [];
|
|
50565
50704
|
opWarnings.push(...responseWarnings);
|
|
50566
50705
|
opWarnings.push(...collectSecuritySchemeWarnings(root, operation));
|
|
50567
|
-
|
|
50706
|
+
const parameterChecks = collectParameterChecks(root, pathItem, operation, version, operationId, path8, opWarnings);
|
|
50707
|
+
const checkedKeys = new Set((parameterChecks ?? []).map((check) => `${check.in}:${check.name.toLowerCase()}`));
|
|
50708
|
+
const decodedKeys = new Set((parameterChecks ?? []).filter((check) => check.decode).map((check) => `${check.in}:${check.name.toLowerCase()}`));
|
|
50709
|
+
opWarnings.push(...collectSerializationWarnings(root, pathItem, operation, decodedKeys));
|
|
50568
50710
|
if (operation.deprecated === true) {
|
|
50569
50711
|
opWarnings.push(`CONTRACT_OPERATION_DEPRECATED: ${lowerMethod.toUpperCase()} ${path8} is marked deprecated in the OpenAPI document`);
|
|
50570
50712
|
}
|
|
@@ -50573,17 +50715,19 @@ function buildContractIndex(root) {
|
|
|
50573
50715
|
opWarnings.push(`CONTRACT_SECURITY_NOT_VALIDATED: security parameter ${parameter.in}:${parameter.name} is not statically required in generated requests`);
|
|
50574
50716
|
}
|
|
50575
50717
|
for (const parameter of requiredParameters.filter((entry) => entry.in === "cookie" && !entry.securityDerived)) {
|
|
50576
|
-
opWarnings.push(`CONTRACT_COOKIE_PARAM_NOT_VALIDATED: required cookie parameter ${parameter.name} is not
|
|
50718
|
+
opWarnings.push(checkedKeys.has(`cookie:${parameter.name.toLowerCase()}`) ? `CONTRACT_COOKIE_PARAM_NOT_VALIDATED: required cookie parameter ${parameter.name} is not included in generated requests; the runtime test fails until the cookie is supplied at send time` : `CONTRACT_COOKIE_PARAM_NOT_VALIDATED: required cookie parameter ${parameter.name} is not included in generated requests and its value is not runtime-validated`);
|
|
50577
50719
|
}
|
|
50578
50720
|
const pathParamWarnings = /* @__PURE__ */ new Set();
|
|
50579
50721
|
for (const param of resolvedParameters(root, pathItem, operation)) {
|
|
50580
50722
|
if (String(param.in || "").toLowerCase() !== "path") continue;
|
|
50581
50723
|
const name = String(param.name || "");
|
|
50582
|
-
if (name
|
|
50724
|
+
if (name && !checkedKeys.has(`path:${name.toLowerCase()}`)) {
|
|
50725
|
+
pathParamWarnings.add(`CONTRACT_PATH_PARAM_NOT_VALIDATED: path parameter ${name} value is not validated at runtime`);
|
|
50726
|
+
}
|
|
50583
50727
|
}
|
|
50584
50728
|
opWarnings.push(...pathParamWarnings);
|
|
50585
50729
|
operations.push({
|
|
50586
|
-
id:
|
|
50730
|
+
id: operationId,
|
|
50587
50731
|
method: lowerMethod.toUpperCase(),
|
|
50588
50732
|
path: path8,
|
|
50589
50733
|
pointer: `/paths/${path8.replace(/~/g, "~0").replace(/\//g, "~1")}/${lowerMethod}`,
|
|
@@ -50591,8 +50735,8 @@ function buildContractIndex(root) {
|
|
|
50591
50735
|
responses: contractResponses,
|
|
50592
50736
|
requiredParameters,
|
|
50593
50737
|
declaredQueryParameters: collectDeclaredQueryParameters(root, pathItem, operation),
|
|
50594
|
-
parameterChecks
|
|
50595
|
-
requestBody: collectRequestBody(root, operation, version,
|
|
50738
|
+
parameterChecks,
|
|
50739
|
+
requestBody: collectRequestBody(root, operation, version, operationId, opWarnings),
|
|
50596
50740
|
security: collectSecurityRuntimeChecks(root, operation),
|
|
50597
50741
|
warnings: opWarnings
|
|
50598
50742
|
});
|
|
@@ -50799,8 +50943,11 @@ function createContractScript(operation, warnings = []) {
|
|
|
50799
50943
|
" if (!actual) return;",
|
|
50800
50944
|
' if (header.unsupported) pm.expect.fail("OpenAPI response header unsupported for " + contract.method + " " + contract.path + ": " + header.unsupported);',
|
|
50801
50945
|
" var headerValidator = validators[selected.key] && validators[selected.key].__headers && validators[selected.key].__headers[String(header.name).toLowerCase()];",
|
|
50802
|
-
" if (headerValidator
|
|
50803
|
-
|
|
50946
|
+
" if (!headerValidator || headerValidator.skip) return;",
|
|
50947
|
+
" var expected;",
|
|
50948
|
+
' if (header.items) { var joined = String(actual).trim(); expected = joined === "" ? [] : joined.split(",").map(function (entry) { return coerceBySchema(entry.trim(), header.items); }); }',
|
|
50949
|
+
" else expected = coerceBySchema(actual, header.schema);",
|
|
50950
|
+
' if (!headerValidator(expected)) pm.expect.fail("OpenAPI response header validation failed for " + header.name + ": " + JSON.stringify(headerValidator.errors || []));',
|
|
50804
50951
|
" });",
|
|
50805
50952
|
"});",
|
|
50806
50953
|
"pm.test('Response body matches OpenAPI body contract', function () {",
|
|
@@ -50856,17 +51003,64 @@ function createContractScript(operation, warnings = []) {
|
|
|
50856
51003
|
...operation.parameterChecks && operation.parameterChecks.length > 0 ? [
|
|
50857
51004
|
"pm.test('Request parameters match OpenAPI schemas', function () {",
|
|
50858
51005
|
' function queryValue(name) { var value; pm.request.url.query.each(function (param) { if (param && param.disabled !== true && String(param.key).toLowerCase() === name) value = param.value === null || param.value === undefined ? "" : String(param.value); }); return value; }',
|
|
51006
|
+
' function queryValues(name) { var values = []; pm.request.url.query.each(function (param) { if (param && param.disabled !== true && String(param.key).toLowerCase() === name) values.push(param.value === null || param.value === undefined ? "" : String(param.value)); }); return values; }',
|
|
50859
51007
|
' function headerValue(name) { var value; pm.request.headers.each(function (header) { if (header && header.disabled !== true && String(header.key).toLowerCase() === String(name).toLowerCase()) value = header.value === null || header.value === undefined ? "" : String(header.value); }); return value; }',
|
|
51008
|
+
' function cookieValue(name) { try { if (pm.cookies && pm.cookies.get) { var jar = pm.cookies.get(String(name)); if (jar !== null && jar !== undefined) return String(jar); } } catch (ignored) {} var raw = requestHeader("Cookie"); if (!raw) return undefined; var found; raw.split(";").forEach(function (part) { var split = part.indexOf("="); if (split === -1) return; if (part.slice(0, split).trim() === String(name)) found = part.slice(split + 1).trim(); }); return found; }',
|
|
51009
|
+
' function requestPathSegments() { var raw = ""; try { raw = typeof pm.request.url.getPath === "function" ? String(pm.request.url.getPath() || "") : ""; } catch (ignored) {} if (!raw) { var path = pm.request.url.path; raw = Array.isArray(path) ? "/" + path.join("/") : String(path || ""); } return raw.split("?")[0].split("#")[0].split("/").filter(function (segment) { return segment.length > 0; }); }',
|
|
51010
|
+
// Server path prefixes sit ahead of the template segments, so the
|
|
51011
|
+
// template aligns against the trailing request segments.
|
|
51012
|
+
' function pathParamValue(name) { var template = String(contract.path).split("/").filter(function (segment) { return segment.length > 0; }); var actual = requestPathSegments(); var offset = actual.length - template.length; if (offset < 0) return undefined; for (var i = 0; i < template.length; i += 1) { if (template[i] === "{" + name + "}") { var segment = actual[offset + i]; try { return decodeURIComponent(segment); } catch (ignored) { return segment; } } } return undefined; }',
|
|
50860
51013
|
' function isPlaceholder(value) { var text = String(value).trim(); return /^<[^<>]*>$/.test(text) || text.indexOf("{{") !== -1; }',
|
|
51014
|
+
' function splitDelimited(value, decode) { if (decode === "csv") return value.split(","); if (decode === "ssv") return value.split(/%20| /); return value.split(/%7C|\\|/i); }',
|
|
51015
|
+
" function decodeComponent(value) { try { return decodeURIComponent(value); } catch (ignored) { return value; } }",
|
|
50861
51016
|
" (contract.parameters || []).forEach(function (param) {",
|
|
50862
51017
|
' var key = param.in + ":" + String(param.name).toLowerCase();',
|
|
50863
51018
|
" var validate = paramValidators[key];",
|
|
50864
51019
|
" if (!validate || validate.skip) return;",
|
|
50865
|
-
|
|
50866
|
-
' if (
|
|
50867
|
-
|
|
50868
|
-
|
|
50869
|
-
'
|
|
51020
|
+
" var value;",
|
|
51021
|
+
' if (param.decode === "multi") {',
|
|
51022
|
+
" var entries = queryValues(String(param.name).toLowerCase());",
|
|
51023
|
+
' if (entries.length === 0) { if (param.required) pm.expect.fail("Required parameter " + param.in + ":" + param.name + " was not sent for " + contract.method + " " + contract.path); return; }',
|
|
51024
|
+
' if (param.allowEmptyValue && entries.length === 1 && entries[0] === "") return;',
|
|
51025
|
+
" if (entries.some(isPlaceholder)) return;",
|
|
51026
|
+
" value = entries.map(function (entry) { return coerceBySchema(decodeComponent(entry), param.items); });",
|
|
51027
|
+
" } else if (param.decode) {",
|
|
51028
|
+
' var joined = param.in === "query" ? queryValue(String(param.name).toLowerCase()) : headerValue(param.name);',
|
|
51029
|
+
' if (joined === undefined) { if (param.required) pm.expect.fail("Required parameter " + param.in + ":" + param.name + " was not sent for " + contract.method + " " + contract.path); return; }',
|
|
51030
|
+
' if (joined === "" && param.allowEmptyValue) return;',
|
|
51031
|
+
" if (isPlaceholder(joined)) return;",
|
|
51032
|
+
' var parts = joined === "" ? [] : splitDelimited(String(joined), param.decode);',
|
|
51033
|
+
// HTTP header lists allow optional whitespace after the comma, so
|
|
51034
|
+
// header-sourced items are trimmed; query values stay literal.
|
|
51035
|
+
' if (param.in === "header") parts = parts.map(function (entry) { return entry.trim(); });',
|
|
51036
|
+
" if (parts.some(isPlaceholder)) return;",
|
|
51037
|
+
// Query values arrive percent-encoded while the server validates the
|
|
51038
|
+
// decoded form; header values are never percent-encoded.
|
|
51039
|
+
' value = parts.map(function (entry) { return coerceBySchema(param.in === "query" ? decodeComponent(entry) : entry, param.items); });',
|
|
51040
|
+
' } else if (param.in === "path") {',
|
|
51041
|
+
" value = pathParamValue(param.name);",
|
|
51042
|
+
" if (value === undefined) return;",
|
|
51043
|
+
' if (isPlaceholder(value) || value.charAt(0) === ":" || value.charAt(0) === "{") return;',
|
|
51044
|
+
" value = coerceBySchema(value, param.schema);",
|
|
51045
|
+
' } else if (param.in === "cookie") {',
|
|
51046
|
+
" value = cookieValue(param.name);",
|
|
51047
|
+
' if (value === undefined) { if (param.required) pm.expect.fail("Required cookie parameter " + param.name + " was not sent for " + contract.method + " " + contract.path); return; }',
|
|
51048
|
+
" if (isPlaceholder(value)) return;",
|
|
51049
|
+
" value = coerceBySchema(value, param.schema);",
|
|
51050
|
+
" } else {",
|
|
51051
|
+
' value = param.in === "query" ? queryValue(String(param.name).toLowerCase()) : headerValue(param.name);',
|
|
51052
|
+
' if (value === undefined) { if (param.required) pm.expect.fail("Required parameter " + param.in + ":" + param.name + " was not sent for " + contract.method + " " + contract.path); return; }',
|
|
51053
|
+
' if (value === "" && param.allowEmptyValue) return;',
|
|
51054
|
+
" if (isPlaceholder(value)) return;",
|
|
51055
|
+
" if (param.content) {",
|
|
51056
|
+
" var parsed;",
|
|
51057
|
+
' try { parsed = JSON.parse(value); } catch (parseError) { pm.expect.fail("Parameter " + param.in + ":" + param.name + " declares JSON content but its value is not parseable JSON for " + contract.method + " " + contract.path); return; }',
|
|
51058
|
+
' if (!validate(parsed)) pm.expect.fail("Parameter " + param.in + ":" + param.name + " failed OpenAPI schema validation for " + contract.method + " " + contract.path + ": " + JSON.stringify(validate.errors || []));',
|
|
51059
|
+
" return;",
|
|
51060
|
+
" }",
|
|
51061
|
+
" value = coerceBySchema(value, param.schema);",
|
|
51062
|
+
" }",
|
|
51063
|
+
' if (!validate(value)) pm.expect.fail("Parameter " + param.in + ":" + param.name + " failed OpenAPI schema validation for " + contract.method + " " + contract.path + ": " + JSON.stringify(validate.errors || []));',
|
|
50870
51064
|
" });",
|
|
50871
51065
|
"});"
|
|
50872
51066
|
] : [],
|
|
@@ -50989,15 +51183,25 @@ function assertStaticRequestShape(operation, request) {
|
|
|
50989
51183
|
if (!contentType) {
|
|
50990
51184
|
throw new Error(`CONTRACT_STATIC_REQUEST_CHECK_FAILED: ${operation.id} missing required request Content-Type`);
|
|
50991
51185
|
}
|
|
50992
|
-
const actual = contentType.toLowerCase().split(";")[0]?.trim();
|
|
50993
|
-
const matches = operation.requestBody.contentTypes.some((expected) => expected.toLowerCase()
|
|
51186
|
+
const actual = contentType.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
51187
|
+
const matches = operation.requestBody.contentTypes.some((expected) => mediaTypeMatchesPattern(expected.toLowerCase(), actual));
|
|
50994
51188
|
if (!matches) {
|
|
50995
51189
|
throw new Error(
|
|
50996
51190
|
`CONTRACT_STATIC_REQUEST_CHECK_FAILED: ${operation.id} request Content-Type ${contentType} does not match ${operation.requestBody.contentTypes.join(", ")}`
|
|
50997
51191
|
);
|
|
50998
51192
|
}
|
|
50999
51193
|
}
|
|
51000
|
-
|
|
51194
|
+
const warnings = collectStaticBodyWarnings(operation, request, contentType);
|
|
51195
|
+
if (operation.requestBody && !operation.requestBody.required && operation.requestBody.contentTypes.length > 0 && hasRequestBody(request) && contentType) {
|
|
51196
|
+
const actual = contentType.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
51197
|
+
const matches = operation.requestBody.contentTypes.some((expected) => mediaTypeMatchesPattern(expected.toLowerCase(), actual));
|
|
51198
|
+
if (!matches) {
|
|
51199
|
+
warnings.push(
|
|
51200
|
+
`CONTRACT_STATIC_REQUEST_CHECK_FAILED: ${operation.id} optional request body Content-Type ${contentType} does not match ${operation.requestBody.contentTypes.join(", ")}`
|
|
51201
|
+
);
|
|
51202
|
+
}
|
|
51203
|
+
}
|
|
51204
|
+
return warnings;
|
|
51001
51205
|
}
|
|
51002
51206
|
function requestBodyFieldNames(request, base) {
|
|
51003
51207
|
const body = asRecord5(request.body);
|
|
@@ -51032,28 +51236,80 @@ function mediaTypeMatchesPattern(pattern, actual) {
|
|
|
51032
51236
|
return false;
|
|
51033
51237
|
});
|
|
51034
51238
|
}
|
|
51239
|
+
function isJsonEncodingContentType(declared) {
|
|
51240
|
+
return declared.split(",").some((candidate) => {
|
|
51241
|
+
const entry = (candidate.split(";")[0] ?? "").trim();
|
|
51242
|
+
return entry === "application/json" || entry.endsWith("+json");
|
|
51243
|
+
});
|
|
51244
|
+
}
|
|
51245
|
+
function isPlaceholderValue(value) {
|
|
51246
|
+
return /^<[^>]*>$/.test(value.trim()) || value.includes("{{");
|
|
51247
|
+
}
|
|
51035
51248
|
function collectStaticEncodingWarnings(operation, request, base, rule) {
|
|
51036
51249
|
const encodings = rule.encodings;
|
|
51037
|
-
if (!encodings
|
|
51250
|
+
if (!encodings) return [];
|
|
51251
|
+
const multipart = base === "multipart/form-data";
|
|
51038
51252
|
const entries = requestBodyEntries(request, base);
|
|
51039
51253
|
if (!entries) return [];
|
|
51040
51254
|
const warnings = [];
|
|
51255
|
+
const part = multipart ? "multipart" : "urlencoded";
|
|
51041
51256
|
for (const [field, encoding] of Object.entries(encodings)) {
|
|
51042
|
-
const entry
|
|
51043
|
-
|
|
51044
|
-
|
|
51045
|
-
|
|
51046
|
-
|
|
51047
|
-
|
|
51048
|
-
|
|
51049
|
-
|
|
51050
|
-
|
|
51051
|
-
|
|
51052
|
-
)
|
|
51053
|
-
|
|
51054
|
-
|
|
51055
|
-
|
|
51056
|
-
|
|
51257
|
+
for (const entry of entries.filter((candidate) => String(candidate.key || "") === field)) {
|
|
51258
|
+
if (multipart && encoding.binary && String(entry.type || "") !== "file") {
|
|
51259
|
+
warnings.push(`CONTRACT_ENCODING_MISMATCH: ${operation.id} generated multipart field ${field} should be a file part per its binary schema`);
|
|
51260
|
+
}
|
|
51261
|
+
if (multipart && encoding.contentType) {
|
|
51262
|
+
const actual = typeof entry.contentType === "string" ? (entry.contentType.toLowerCase().split(";")[0] ?? "").trim() : "";
|
|
51263
|
+
if (!actual) {
|
|
51264
|
+
warnings.push(
|
|
51265
|
+
`CONTRACT_ENCODING_MISMATCH: ${operation.id} generated multipart field ${field} does not declare Content-Type ${encoding.contentType} from its encoding object`
|
|
51266
|
+
);
|
|
51267
|
+
} else if (!mediaTypeMatchesPattern(encoding.contentType, actual)) {
|
|
51268
|
+
warnings.push(
|
|
51269
|
+
`CONTRACT_ENCODING_MISMATCH: ${operation.id} generated multipart field ${field} Content-Type ${actual} does not match declared encoding ${encoding.contentType}`
|
|
51270
|
+
);
|
|
51271
|
+
}
|
|
51272
|
+
}
|
|
51273
|
+
if (encoding.contentType && isJsonEncodingContentType(encoding.contentType) && String(entry.type || "text") !== "file") {
|
|
51274
|
+
const value = typeof entry.value === "string" ? entry.value : "";
|
|
51275
|
+
if (value.trim() && !isPlaceholderValue(value)) {
|
|
51276
|
+
try {
|
|
51277
|
+
JSON.parse(value);
|
|
51278
|
+
} catch {
|
|
51279
|
+
warnings.push(
|
|
51280
|
+
`CONTRACT_ENCODING_MISMATCH: ${operation.id} generated ${part} field ${field} declares JSON encoding ${encoding.contentType} but its value is not parseable JSON`
|
|
51281
|
+
);
|
|
51282
|
+
}
|
|
51283
|
+
}
|
|
51284
|
+
}
|
|
51285
|
+
}
|
|
51286
|
+
}
|
|
51287
|
+
return warnings;
|
|
51288
|
+
}
|
|
51289
|
+
function coerceFormValue(value, schema2) {
|
|
51290
|
+
const record = asRecord5(schema2);
|
|
51291
|
+
const type2 = record?.type;
|
|
51292
|
+
const types2 = Array.isArray(type2) ? type2 : [type2];
|
|
51293
|
+
if ((types2.includes("integer") || types2.includes("number")) && /^-?[0-9]+([.][0-9]+)?([eE][+-]?[0-9]+)?$/.test(value.trim())) return Number(value);
|
|
51294
|
+
if (types2.includes("boolean") && (value === "true" || value === "false")) return value === "true";
|
|
51295
|
+
return value;
|
|
51296
|
+
}
|
|
51297
|
+
function collectStaticFieldSchemaWarnings(operation, request, base, rule) {
|
|
51298
|
+
const fieldSchemas = rule.fieldSchemas;
|
|
51299
|
+
if (!fieldSchemas) return [];
|
|
51300
|
+
const entries = requestBodyEntries(request, base);
|
|
51301
|
+
if (!entries) return [];
|
|
51302
|
+
const part = base === "multipart/form-data" ? "multipart" : "urlencoded";
|
|
51303
|
+
const warnings = [];
|
|
51304
|
+
for (const [field, schema2] of Object.entries(fieldSchemas)) {
|
|
51305
|
+
const validate2 = compileSchemaValidator(schema2);
|
|
51306
|
+
if (!validate2) continue;
|
|
51307
|
+
for (const entry of entries.filter((candidate) => String(candidate.key || "") === field)) {
|
|
51308
|
+
if (String(entry.type || "text") === "file") continue;
|
|
51309
|
+
const value = typeof entry.value === "string" ? entry.value : "";
|
|
51310
|
+
if (!value.trim() || isPlaceholderValue(value)) continue;
|
|
51311
|
+
if (!validate2(coerceFormValue(value, schema2))) {
|
|
51312
|
+
warnings.push(`CONTRACT_FORM_FIELD_SCHEMA_MISMATCH: ${operation.id} generated ${part} field ${field} value does not match its schema`);
|
|
51057
51313
|
}
|
|
51058
51314
|
}
|
|
51059
51315
|
}
|
|
@@ -51065,7 +51321,10 @@ function collectStaticBodyWarnings(operation, request, contentType) {
|
|
|
51065
51321
|
const base = (contentType || "").toLowerCase().split(";")[0]?.trim() ?? "";
|
|
51066
51322
|
const rule = rules[base];
|
|
51067
51323
|
if (!rule) return [];
|
|
51068
|
-
const warnings = [
|
|
51324
|
+
const warnings = [
|
|
51325
|
+
...collectStaticEncodingWarnings(operation, request, base, rule),
|
|
51326
|
+
...collectStaticFieldSchemaWarnings(operation, request, base, rule)
|
|
51327
|
+
];
|
|
51069
51328
|
const names = requestBodyFieldNames(request, base);
|
|
51070
51329
|
if (!names) return warnings;
|
|
51071
51330
|
const present = new Set(names);
|