chore(vendor): import pi 0.85.1
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: d981de1229ef899957bbe968bc8dcda02a21f477
This commit is contained in:
50
third_party/pi/packages/chord/src/json.ts
vendored
Normal file
50
third_party/pi/packages/chord/src/json.ts
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import type { JsonValue } from "./types.ts";
|
||||
|
||||
/** Return whether a value is finite strict JSON with plain objects and no cycles. */
|
||||
export function isJsonValue(value: unknown): value is JsonValue {
|
||||
return check(value, new Set<object>(), 0);
|
||||
}
|
||||
|
||||
function check(value: unknown, ancestors: Set<object>, depth: number): boolean {
|
||||
if (depth > 512) return false;
|
||||
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
||||
if (typeof value === "number") return Number.isFinite(value);
|
||||
if (Array.isArray(value)) {
|
||||
const keys = Reflect.ownKeys(value);
|
||||
if (keys.length !== value.length + 1 || keys.some((key) => typeof key !== "string")) return false;
|
||||
if (ancestors.has(value)) return false;
|
||||
ancestors.add(value);
|
||||
try {
|
||||
for (let index = 0; index < value.length; index++) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
||||
if (
|
||||
descriptor === undefined ||
|
||||
!descriptor.enumerable ||
|
||||
!("value" in descriptor) ||
|
||||
!check(descriptor.value, ancestors, depth + 1)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
ancestors.delete(value);
|
||||
}
|
||||
}
|
||||
if (typeof value !== "object" || value === null) return false;
|
||||
const prototype = Object.getPrototypeOf(value);
|
||||
if (prototype !== Object.prototype && prototype !== null) return false;
|
||||
if (Reflect.ownKeys(value).some((key) => typeof key !== "string")) return false;
|
||||
if (ancestors.has(value)) return false;
|
||||
ancestors.add(value);
|
||||
try {
|
||||
for (const descriptor of Object.values(Object.getOwnPropertyDescriptors(value))) {
|
||||
if (!descriptor.enumerable || !("value" in descriptor) || !check(descriptor.value, ancestors, depth + 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
ancestors.delete(value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user