fix(ai): also strip sibling type-specific keys during CCA mixed-type collapse
Address review feedback: - Replace `as string` assertion with typed `chosenType` local - Strip sibling keys from nextSchema that were copied via copySchemaWithout but belong to a type other than the chosen one (e.g. sibling `items` on a now-string-typed schema) - Export ALL_CCA_TYPE_SPECIFIC_KEYS from fields.ts for sibling filtering - Add regression test for the sibling-key edge case
This commit is contained in:
@@ -154,6 +154,22 @@ export const CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS: Record<string, Record<string,
|
||||
null: {},
|
||||
};
|
||||
|
||||
/**
|
||||
* Flat set of every type-specific key across all CCA types.
|
||||
* Used to identify sibling keys that need filtering during mixed-type collapse.
|
||||
*/
|
||||
export const ALL_CCA_TYPE_SPECIFIC_KEYS: Record<string, true> = buildAllCcaTypeSpecificKeys();
|
||||
|
||||
function buildAllCcaTypeSpecificKeys(): Record<string, true> {
|
||||
const all: Record<string, true> = {};
|
||||
for (const typeKeys of Object.values(CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS)) {
|
||||
for (const key in typeKeys) {
|
||||
all[key] = true;
|
||||
}
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cloud Code Assist shared schema keys allowed on any type.
|
||||
* Used alongside CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS for CCA combiner collapsing.
|
||||
|
||||
@@ -11,6 +11,7 @@ import { dereferenceJsonSchema } from "./dereference";
|
||||
import { upgradeJsonSchemaTo202012 } from "./draft";
|
||||
import { areJsonValuesEqual, mergePropertySchemas } from "./equality";
|
||||
import {
|
||||
ALL_CCA_TYPE_SPECIFIC_KEYS,
|
||||
CLOUD_CODE_ASSIST_SHARED_SCHEMA_KEYS,
|
||||
CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS,
|
||||
COMBINATOR_KEYS,
|
||||
@@ -501,11 +502,26 @@ function collapseMixedTypeCombinerVariants(schema: JsonObject, combiner: "anyOf"
|
||||
if (variantTypes.length < 2 || variantTypes.every(type => type === "object")) {
|
||||
return schema;
|
||||
}
|
||||
|
||||
const nextSchema = copySchemaWithout(schema, combiner);
|
||||
const nonNullTypes = variantTypes.filter(t => t !== "null");
|
||||
nextSchema.type = nonNullTypes[0] ?? variantTypes[0];
|
||||
const chosenTypeAllowedKeys = CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS[nextSchema.type as string] ?? {};
|
||||
const chosenType: string = nonNullTypes[0] ?? variantTypes[0];
|
||||
nextSchema.type = chosenType;
|
||||
const chosenTypeAllowedKeys = CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS[chosenType] ?? {};
|
||||
|
||||
// Strip sibling keys that were copied from the parent and belong to a
|
||||
// different type (e.g. `items` sibling on a now-string-typed schema).
|
||||
for (const key in nextSchema) {
|
||||
if (!Object.hasOwn(nextSchema, key)) continue;
|
||||
if (key === "type") continue;
|
||||
if (
|
||||
Object.hasOwn(ALL_CCA_TYPE_SPECIFIC_KEYS, key) &&
|
||||
!Object.hasOwn(chosenTypeAllowedKeys, key) &&
|
||||
!Object.hasOwn(CLOUD_CODE_ASSIST_SHARED_SCHEMA_KEYS, key)
|
||||
) {
|
||||
delete nextSchema[key];
|
||||
}
|
||||
}
|
||||
|
||||
for (const key in mergedVariantFields) {
|
||||
if (!Object.hasOwn(mergedVariantFields, key)) continue;
|
||||
// Drop type-specific keys that don't belong to the chosen type
|
||||
|
||||
@@ -979,6 +979,21 @@ describe("normalizeSchemaForCCA", () => {
|
||||
description: "pr number, url, or branch",
|
||||
});
|
||||
});
|
||||
|
||||
it("strips sibling type-specific keys copied from parent when mixed-type collapse picks opposing type", () => {
|
||||
// Edge case: parent has a sibling `items` outside the anyOf,
|
||||
// and the chosen type is string. The sibling must be stripped.
|
||||
const normalized = normalizeSchemaForCCA({
|
||||
anyOf: [{ type: "string" }, { type: "array", items: { type: "number" } }],
|
||||
items: { type: "string" },
|
||||
description: "pr number, url, or branch",
|
||||
});
|
||||
|
||||
expect(normalized).toEqual({
|
||||
type: "string",
|
||||
description: "pr number, url, or branch",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user