mirror of
https://github.com/github/codeql-action.git
synced 2026-10-03 17:41:28 +00:00
Track invalid keys, and use more standard JSON path notation
This commit is contained in:
19
lib/entry-points.js
generated
19
lib/entry-points.js
generated
@@ -144509,7 +144509,7 @@ function isStringOrUndefined(value) {
|
||||
return value === void 0 || isString(value);
|
||||
}
|
||||
function defaultCheck(validate) {
|
||||
return (arg) => ({ unknownKeys: [], valid: validate(arg) });
|
||||
return (arg) => ({ unknownKeys: [], invalidKeys: [], valid: validate(arg) });
|
||||
}
|
||||
function makeValidator(validate, required = true) {
|
||||
return {
|
||||
@@ -144541,15 +144541,18 @@ function validateSchema(schema, obj) {
|
||||
function successfulCheckSchema() {
|
||||
return {
|
||||
valid: true,
|
||||
unknownKeys: []
|
||||
unknownKeys: [],
|
||||
invalidKeys: []
|
||||
};
|
||||
}
|
||||
function checkSchema(schema, obj, options = {}, path29 = "") {
|
||||
const result = successfulCheckSchema();
|
||||
const inputKeys = new Set(Object.keys(obj));
|
||||
const invalidKeys = /* @__PURE__ */ new Set();
|
||||
for (const [key, validator] of Object.entries(schema)) {
|
||||
const hasKey = key in obj;
|
||||
inputKeys.delete(key);
|
||||
invalidKeys.add(key);
|
||||
if (validator.required && !hasKey) {
|
||||
result.valid = false;
|
||||
if (options.failFast) {
|
||||
@@ -144565,8 +144568,12 @@ function checkSchema(schema, obj, options = {}, path29 = "") {
|
||||
continue;
|
||||
}
|
||||
if (hasKey) {
|
||||
const checkResult = validator.check(obj[key], `${path29}${key}.`);
|
||||
const checkResult = validator.check(obj[key], `${path29}.${key}`);
|
||||
result.unknownKeys.push(...checkResult.unknownKeys);
|
||||
result.invalidKeys.push(...checkResult.invalidKeys);
|
||||
if (checkResult.invalidKeys.length > 0) {
|
||||
invalidKeys.delete(key);
|
||||
}
|
||||
if (!checkResult.valid) {
|
||||
result.valid = false;
|
||||
if (options.failFast) {
|
||||
@@ -144575,9 +144582,13 @@ function checkSchema(schema, obj, options = {}, path29 = "") {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
invalidKeys.delete(key);
|
||||
}
|
||||
for (const remainingKey of inputKeys) {
|
||||
result.unknownKeys.push(`${path29}${remainingKey}`);
|
||||
result.unknownKeys.push(`${path29}.${remainingKey}`);
|
||||
}
|
||||
for (const invalidKey of invalidKeys) {
|
||||
result.invalidKeys.push(`${path29}.${invalidKey}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -121,6 +121,22 @@ test("validateSchema - checkSchema reports unknown keys", async (t) => {
|
||||
t.true(result.valid);
|
||||
t.deepEqual(
|
||||
result.unknownKeys.sort(),
|
||||
["extraKey", "rootKey.nestedExtraKey"].sort(),
|
||||
[".extraKey", ".rootKey.nestedExtraKey"].sort(),
|
||||
);
|
||||
});
|
||||
|
||||
test("validateSchema - checkSchema reports invalid keys", async (t) => {
|
||||
const result = json.checkSchema(checkSchemaTestSchema, {
|
||||
rootKey: {
|
||||
objectKey: {
|
||||
arrayKey: ["foo"],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
t.false(result.valid);
|
||||
t.deepEqual(
|
||||
result.invalidKeys.sort(),
|
||||
[".rootKey.objectKey.arrayKey[0]"].sort(),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -55,7 +55,7 @@ export type Validator<T> = {
|
||||
function defaultCheck(
|
||||
validate: (val: unknown) => val is any,
|
||||
): (arg: unknown) => CheckSchemaResult {
|
||||
return (arg) => ({ unknownKeys: [], valid: validate(arg) });
|
||||
return (arg) => ({ unknownKeys: [], invalidKeys: [], valid: validate(arg) });
|
||||
}
|
||||
|
||||
function makeValidator<T>(
|
||||
@@ -88,20 +88,24 @@ export function array<T>(validator: Validator<T>) {
|
||||
check: (val: unknown, path: string) => {
|
||||
const result: CheckSchemaResult = successfulCheckSchema();
|
||||
|
||||
// The value must be an array.
|
||||
if (!isArray(val)) {
|
||||
result.valid = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Validate all elements of the array.
|
||||
let index = 0;
|
||||
for (const e of val) {
|
||||
const eResult = validator.check(e, `${path}[${index}].`);
|
||||
const elementPath = `${path}[${index}]`;
|
||||
const eResult = validator.check(e, `${elementPath}`);
|
||||
|
||||
result.unknownKeys.push(...eResult.unknownKeys);
|
||||
index++;
|
||||
|
||||
if (!eResult.valid) {
|
||||
result.valid = false;
|
||||
result.invalidKeys.push(elementPath);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -212,6 +216,8 @@ export interface CheckSchemaResult {
|
||||
valid: boolean;
|
||||
/** Unknown keys that were found during validation. */
|
||||
unknownKeys: string[];
|
||||
/** Known keys that failed validation. */
|
||||
invalidKeys: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,6 +227,7 @@ function successfulCheckSchema(): CheckSchemaResult {
|
||||
return {
|
||||
valid: true,
|
||||
unknownKeys: [],
|
||||
invalidKeys: [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -231,6 +238,7 @@ function invalidCheckSchema(): CheckSchemaResult {
|
||||
return {
|
||||
valid: false,
|
||||
unknownKeys: [],
|
||||
invalidKeys: [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -242,6 +250,7 @@ export function checkSchema<S extends Schema>(
|
||||
): CheckSchemaResult {
|
||||
const result: CheckSchemaResult = successfulCheckSchema();
|
||||
const inputKeys = new Set(Object.keys(obj));
|
||||
const invalidKeys = new Set();
|
||||
|
||||
for (const [key, validator] of Object.entries(schema)) {
|
||||
const hasKey = key in obj;
|
||||
@@ -249,6 +258,10 @@ export function checkSchema<S extends Schema>(
|
||||
// Remove key from set of unrecognised keys.
|
||||
inputKeys.delete(key);
|
||||
|
||||
// Add the key to the set of invalid keys. We remove it later once
|
||||
// it passes validation.
|
||||
invalidKeys.add(key);
|
||||
|
||||
// If the property is required, but absent, fail.
|
||||
if (validator.required && !hasKey) {
|
||||
result.valid = false;
|
||||
@@ -271,9 +284,16 @@ export function checkSchema<S extends Schema>(
|
||||
|
||||
// If the property is present, validate it.
|
||||
if (hasKey) {
|
||||
const checkResult = validator.check(obj[key], `${path}${key}.`);
|
||||
const checkResult = validator.check(obj[key], `${path}.${key}`);
|
||||
|
||||
result.unknownKeys.push(...checkResult.unknownKeys);
|
||||
result.invalidKeys.push(...checkResult.invalidKeys);
|
||||
|
||||
// If we have invalid keys from the validator, then that means that
|
||||
// we have a more specific key than `key`. Remove `key` from the results.
|
||||
if (checkResult.invalidKeys.length > 0) {
|
||||
invalidKeys.delete(key);
|
||||
}
|
||||
|
||||
if (!checkResult.valid) {
|
||||
result.valid = false;
|
||||
@@ -286,11 +306,17 @@ export function checkSchema<S extends Schema>(
|
||||
}
|
||||
|
||||
// If we reach this point, the key has been successfully validated.
|
||||
invalidKeys.delete(key);
|
||||
}
|
||||
|
||||
// If there are any remaining keys in `inputKeys`, add them to `unknownKeys`.
|
||||
for (const remainingKey of inputKeys) {
|
||||
result.unknownKeys.push(`${path}${remainingKey}`);
|
||||
result.unknownKeys.push(`${path}.${remainingKey}`);
|
||||
}
|
||||
|
||||
// If there are any remaining keys in `invalidKeys`, add them to the result.
|
||||
for (const invalidKey of invalidKeys) {
|
||||
result.invalidKeys.push(`${path}.${invalidKey}`);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user