zod 4.5.3 → 4.6.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/compile.cjs +19 -0
- package/index.cjs +19 -0
- package/locales/index.cjs +19 -0
- package/mini/index.cjs +19 -0
- package/package.json +8 -7
- package/src/v3/helpers/errorUtil.ts +1 -1
- package/src/v4/classic/checks.ts +0 -1
- package/src/v4/classic/external.ts +2 -0
- package/src/v4/classic/from-json-schema.ts +248 -25
- package/src/v4/classic/schemas.ts +255 -164
- package/src/v4/classic/tests/assignability.test.ts +59 -9
- package/src/v4/classic/tests/bigint.test.ts +6 -0
- package/src/v4/classic/tests/continuability.test.ts +2 -2
- package/src/v4/classic/tests/cyclic-data.test.ts +316 -0
- package/src/v4/classic/tests/default.test.ts +46 -0
- package/src/v4/classic/tests/enum.test.ts +9 -0
- package/src/v4/classic/tests/error.test.ts +130 -1
- package/src/v4/classic/tests/firstparty.test.ts +4 -0
- package/src/v4/classic/tests/from-json-schema.test.ts +157 -0
- package/src/v4/classic/tests/iban.test.ts +81 -0
- package/src/v4/classic/tests/instance-footprint.test.ts +18 -2
- package/src/v4/classic/tests/instanceof.test.ts +27 -7
- package/src/v4/classic/tests/issue-schema.test.ts +88 -56
- package/src/v4/classic/tests/object.test.ts +56 -0
- package/src/v4/classic/tests/optin-ladder.test.ts +3 -2
- package/src/v4/classic/tests/properties.test.ts +225 -0
- package/src/v4/classic/tests/recursive-types.test.ts +1 -1
- package/src/v4/classic/tests/standard-schema.test.ts +19 -0
- package/src/v4/classic/tests/string.test.ts +25 -0
- package/src/v4/classic/tests/template-literal.test.ts +33 -1
- package/src/v4/classic/tests/to-json-schema.test.ts +147 -3
- package/src/v4/classic/tests/validate.test.ts +569 -0
- package/src/v4/core/api.ts +30 -6
- package/src/v4/core/checks.ts +1 -101
- package/src/v4/core/compile.ts +193 -81
- package/src/v4/core/doc.ts +6 -2
- package/src/v4/core/errors.ts +3 -6
- package/src/v4/core/json-schema-generator.ts +2 -2
- package/src/v4/core/json-schema-processors.ts +226 -68
- package/src/v4/core/memoizer.ts +162 -36
- package/src/v4/core/parse.ts +37 -16
- package/src/v4/core/regexes.ts +10 -4
- package/src/v4/core/schemas.ts +314 -83
- package/src/v4/core/tests/cached.test.ts +54 -0
- package/src/v4/core/tests/compile-generative.test.ts +445 -0
- package/src/v4/core/tests/compile.test.ts +222 -2
- package/src/v4/core/tests/email-regex.test.ts +140 -0
- package/src/v4/core/tests/polyfill-collision.test.ts +46 -0
- package/src/v4/core/to-json-schema.ts +10 -8
- package/src/v4/core/util.ts +222 -147
- package/src/v4/core/versions.ts +2 -2
- package/src/v4/core/visit.ts +11 -0
- package/src/v4/locales/ar.ts +1 -0
- package/src/v4/locales/az.ts +1 -0
- package/src/v4/locales/be.ts +1 -0
- package/src/v4/locales/bg.ts +1 -0
- package/src/v4/locales/bn.ts +1 -0
- package/src/v4/locales/ca.ts +1 -0
- package/src/v4/locales/ckb.ts +1 -0
- package/src/v4/locales/cs.ts +1 -0
- package/src/v4/locales/da.ts +1 -0
- package/src/v4/locales/de.ts +1 -0
- package/src/v4/locales/el.ts +1 -0
- package/src/v4/locales/en.ts +1 -0
- package/src/v4/locales/eo.ts +1 -0
- package/src/v4/locales/es.ts +1 -0
- package/src/v4/locales/fa.ts +1 -0
- package/src/v4/locales/fi.ts +1 -0
- package/src/v4/locales/fr-CA.ts +1 -0
- package/src/v4/locales/fr.ts +1 -0
- package/src/v4/locales/gu.ts +1 -0
- package/src/v4/locales/he.ts +1 -0
- package/src/v4/locales/hi.ts +1 -0
- package/src/v4/locales/hr.ts +1 -0
- package/src/v4/locales/hu.ts +1 -0
- package/src/v4/locales/hy.ts +1 -0
- package/src/v4/locales/id.ts +1 -0
- package/src/v4/locales/is.ts +1 -0
- package/src/v4/locales/it.ts +1 -0
- package/src/v4/locales/ja.ts +1 -0
- package/src/v4/locales/ka.ts +1 -0
- package/src/v4/locales/km.ts +1 -0
- package/src/v4/locales/kn.ts +1 -0
- package/src/v4/locales/ko.ts +1 -0
- package/src/v4/locales/lt.ts +1 -0
- package/src/v4/locales/mk.ts +1 -0
- package/src/v4/locales/ms.ts +1 -0
- package/src/v4/locales/ne.ts +1 -0
- package/src/v4/locales/nl.ts +1 -0
- package/src/v4/locales/nn.ts +1 -0
- package/src/v4/locales/no.ts +1 -0
- package/src/v4/locales/ota.ts +1 -0
- package/src/v4/locales/pl.ts +1 -0
- package/src/v4/locales/ps.ts +1 -0
- package/src/v4/locales/pt-BR.ts +1 -0
- package/src/v4/locales/pt.ts +1 -0
- package/src/v4/locales/ro.ts +1 -0
- package/src/v4/locales/ru.ts +1 -0
- package/src/v4/locales/sk.ts +1 -0
- package/src/v4/locales/sl.ts +1 -0
- package/src/v4/locales/sv.ts +1 -0
- package/src/v4/locales/ta.ts +1 -0
- package/src/v4/locales/th.ts +1 -0
- package/src/v4/locales/tk.ts +1 -0
- package/src/v4/locales/tr.ts +1 -0
- package/src/v4/locales/uk.ts +1 -0
- package/src/v4/locales/ur.ts +1 -0
- package/src/v4/locales/uz.ts +1 -0
- package/src/v4/locales/vi.ts +1 -0
- package/src/v4/locales/yo.ts +1 -0
- package/src/v4/locales/zh-CN.ts +1 -0
- package/src/v4/locales/zh-TW.ts +1 -0
- package/src/v4/mini/checks.ts +0 -1
- package/src/v4/mini/external.ts +2 -0
- package/src/v4/mini/schemas.ts +38 -2
- package/src/v4/mini/tests/checks.test.ts +1 -1
- package/src/v4/mini/tests/computed.test.ts +11 -17
- package/src/v4/mini/tests/index.test.ts +8 -0
- package/src/v4/mini/tests/string.test.ts +16 -0
- package/v3/ZodError.cjs +19 -0
- package/v3/errors.cjs +19 -0
- package/v3/external.cjs +19 -0
- package/v3/helpers/enumUtil.cjs +19 -0
- package/v3/helpers/errorUtil.cjs +20 -1
- package/v3/helpers/errorUtil.js +1 -1
- package/v3/helpers/parseUtil.cjs +19 -0
- package/v3/helpers/partialUtil.cjs +19 -0
- package/v3/helpers/typeAliases.cjs +19 -0
- package/v3/helpers/util.cjs +19 -0
- package/v3/index.cjs +19 -0
- package/v3/standard-schema.cjs +19 -0
- package/v3/types.cjs +19 -0
- package/v4/classic/checks.cjs +20 -2
- package/v4/classic/checks.d.cts +1 -1
- package/v4/classic/checks.d.ts +1 -1
- package/v4/classic/checks.js +1 -1
- package/v4/classic/coerce.cjs +19 -0
- package/v4/classic/compat.cjs +19 -0
- package/v4/classic/deep-partial.cjs +19 -0
- package/v4/classic/errors.cjs +19 -0
- package/v4/classic/external.cjs +22 -1
- package/v4/classic/external.d.cts +1 -1
- package/v4/classic/external.d.ts +1 -1
- package/v4/classic/external.js +1 -1
- package/v4/classic/from-json-schema.cjs +264 -24
- package/v4/classic/from-json-schema.js +245 -24
- package/v4/classic/in-out.cjs +19 -0
- package/v4/classic/index.cjs +19 -0
- package/v4/classic/iso.cjs +19 -0
- package/v4/classic/parse.cjs +19 -0
- package/v4/classic/schemas.cjs +100 -31
- package/v4/classic/schemas.d.cts +17 -1
- package/v4/classic/schemas.d.ts +17 -1
- package/v4/classic/schemas.js +77 -29
- package/v4/core/api.cjs +37 -2
- package/v4/core/api.d.cts +6 -4
- package/v4/core/api.d.ts +6 -4
- package/v4/core/api.js +17 -2
- package/v4/core/checks.cjs +19 -96
- package/v4/core/checks.d.cts +1 -1
- package/v4/core/checks.d.ts +1 -1
- package/v4/core/checks.js +0 -96
- package/v4/core/compile.cjs +164 -65
- package/v4/core/compile.d.cts +18 -4
- package/v4/core/compile.d.ts +18 -4
- package/v4/core/compile.js +145 -66
- package/v4/core/core.cjs +19 -0
- package/v4/core/doc.cjs +26 -2
- package/v4/core/doc.js +7 -2
- package/v4/core/errors.cjs +21 -5
- package/v4/core/errors.js +2 -5
- package/v4/core/index.cjs +19 -0
- package/v4/core/json-schema-generator.cjs +20 -1
- package/v4/core/json-schema-generator.js +2 -2
- package/v4/core/json-schema-processors.cjs +215 -63
- package/v4/core/json-schema-processors.d.cts +17 -0
- package/v4/core/json-schema-processors.d.ts +17 -0
- package/v4/core/json-schema-processors.js +195 -64
- package/v4/core/json-schema.cjs +19 -0
- package/v4/core/memoizer.cjs +204 -36
- package/v4/core/memoizer.js +162 -36
- package/v4/core/parse.cjs +56 -16
- package/v4/core/parse.js +37 -16
- package/v4/core/regexes.cjs +29 -6
- package/v4/core/regexes.d.cts +2 -0
- package/v4/core/regexes.d.ts +2 -0
- package/v4/core/regexes.js +8 -4
- package/v4/core/registries.cjs +19 -0
- package/v4/core/schemas.cjs +285 -66
- package/v4/core/schemas.d.cts +34 -3
- package/v4/core/schemas.d.ts +34 -3
- package/v4/core/schemas.js +264 -65
- package/v4/core/standard-schema.cjs +19 -0
- package/v4/core/to-json-schema.cjs +29 -7
- package/v4/core/to-json-schema.d.cts +7 -3
- package/v4/core/to-json-schema.d.ts +7 -3
- package/v4/core/to-json-schema.js +8 -7
- package/v4/core/util.cjs +181 -143
- package/v4/core/util.d.cts +25 -4
- package/v4/core/util.d.ts +25 -4
- package/v4/core/util.js +160 -143
- package/v4/core/versions.cjs +21 -2
- package/v4/core/versions.d.cts +1 -1
- package/v4/core/versions.d.ts +1 -1
- package/v4/core/versions.js +2 -2
- package/v4/core/visit.cjs +31 -0
- package/v4/core/visit.js +12 -0
- package/v4/index.cjs +19 -0
- package/v4/locales/ar.cjs +1 -0
- package/v4/locales/ar.js +1 -0
- package/v4/locales/az.cjs +1 -0
- package/v4/locales/az.js +1 -0
- package/v4/locales/be.cjs +1 -0
- package/v4/locales/be.js +1 -0
- package/v4/locales/bg.cjs +1 -0
- package/v4/locales/bg.js +1 -0
- package/v4/locales/bn.cjs +1 -0
- package/v4/locales/bn.js +1 -0
- package/v4/locales/ca.cjs +1 -0
- package/v4/locales/ca.js +1 -0
- package/v4/locales/ckb.cjs +1 -0
- package/v4/locales/ckb.js +1 -0
- package/v4/locales/cs.cjs +1 -0
- package/v4/locales/cs.js +1 -0
- package/v4/locales/da.cjs +1 -0
- package/v4/locales/da.js +1 -0
- package/v4/locales/de.cjs +1 -0
- package/v4/locales/de.js +1 -0
- package/v4/locales/el.cjs +1 -0
- package/v4/locales/el.js +1 -0
- package/v4/locales/en.cjs +1 -0
- package/v4/locales/en.js +1 -0
- package/v4/locales/eo.cjs +1 -0
- package/v4/locales/eo.js +1 -0
- package/v4/locales/es.cjs +1 -0
- package/v4/locales/es.js +1 -0
- package/v4/locales/fa.cjs +1 -0
- package/v4/locales/fa.js +1 -0
- package/v4/locales/fi.cjs +1 -0
- package/v4/locales/fi.js +1 -0
- package/v4/locales/fr-CA.cjs +1 -0
- package/v4/locales/fr-CA.js +1 -0
- package/v4/locales/fr.cjs +1 -0
- package/v4/locales/fr.js +1 -0
- package/v4/locales/gu.cjs +1 -0
- package/v4/locales/gu.js +1 -0
- package/v4/locales/he.cjs +1 -0
- package/v4/locales/he.js +1 -0
- package/v4/locales/hi.cjs +1 -0
- package/v4/locales/hi.js +1 -0
- package/v4/locales/hr.cjs +1 -0
- package/v4/locales/hr.js +1 -0
- package/v4/locales/hu.cjs +1 -0
- package/v4/locales/hu.js +1 -0
- package/v4/locales/hy.cjs +1 -0
- package/v4/locales/hy.js +1 -0
- package/v4/locales/id.cjs +1 -0
- package/v4/locales/id.js +1 -0
- package/v4/locales/index.cjs +19 -0
- package/v4/locales/is.cjs +1 -0
- package/v4/locales/is.js +1 -0
- package/v4/locales/it.cjs +1 -0
- package/v4/locales/it.js +1 -0
- package/v4/locales/ja.cjs +1 -0
- package/v4/locales/ja.js +1 -0
- package/v4/locales/ka.cjs +1 -0
- package/v4/locales/ka.js +1 -0
- package/v4/locales/km.cjs +1 -0
- package/v4/locales/km.js +1 -0
- package/v4/locales/kn.cjs +1 -0
- package/v4/locales/kn.js +1 -0
- package/v4/locales/ko.cjs +1 -0
- package/v4/locales/ko.js +1 -0
- package/v4/locales/lt.cjs +1 -0
- package/v4/locales/lt.js +1 -0
- package/v4/locales/mk.cjs +1 -0
- package/v4/locales/mk.js +1 -0
- package/v4/locales/ms.cjs +1 -0
- package/v4/locales/ms.js +1 -0
- package/v4/locales/ne.cjs +1 -0
- package/v4/locales/ne.js +1 -0
- package/v4/locales/nl.cjs +1 -0
- package/v4/locales/nl.js +1 -0
- package/v4/locales/nn.cjs +1 -0
- package/v4/locales/nn.js +1 -0
- package/v4/locales/no.cjs +1 -0
- package/v4/locales/no.js +1 -0
- package/v4/locales/ota.cjs +1 -0
- package/v4/locales/ota.js +1 -0
- package/v4/locales/pl.cjs +1 -0
- package/v4/locales/pl.js +1 -0
- package/v4/locales/ps.cjs +1 -0
- package/v4/locales/ps.js +1 -0
- package/v4/locales/pt-BR.cjs +1 -0
- package/v4/locales/pt-BR.js +1 -0
- package/v4/locales/pt.cjs +1 -0
- package/v4/locales/pt.js +1 -0
- package/v4/locales/ro.cjs +1 -0
- package/v4/locales/ro.js +1 -0
- package/v4/locales/ru.cjs +1 -0
- package/v4/locales/ru.js +1 -0
- package/v4/locales/sk.cjs +1 -0
- package/v4/locales/sk.js +1 -0
- package/v4/locales/sl.cjs +1 -0
- package/v4/locales/sl.js +1 -0
- package/v4/locales/sv.cjs +1 -0
- package/v4/locales/sv.js +1 -0
- package/v4/locales/ta.cjs +1 -0
- package/v4/locales/ta.js +1 -0
- package/v4/locales/th.cjs +1 -0
- package/v4/locales/th.js +1 -0
- package/v4/locales/tk.cjs +1 -0
- package/v4/locales/tk.js +1 -0
- package/v4/locales/tr.cjs +1 -0
- package/v4/locales/tr.js +1 -0
- package/v4/locales/uk.cjs +1 -0
- package/v4/locales/uk.js +1 -0
- package/v4/locales/ur.cjs +1 -0
- package/v4/locales/ur.js +1 -0
- package/v4/locales/uz.cjs +1 -0
- package/v4/locales/uz.js +1 -0
- package/v4/locales/vi.cjs +1 -0
- package/v4/locales/vi.js +1 -0
- package/v4/locales/yo.cjs +1 -0
- package/v4/locales/yo.js +1 -0
- package/v4/locales/zh-CN.cjs +1 -0
- package/v4/locales/zh-CN.js +1 -0
- package/v4/locales/zh-TW.cjs +1 -0
- package/v4/locales/zh-TW.js +1 -0
- package/v4/mini/checks.cjs +20 -2
- package/v4/mini/checks.d.cts +1 -1
- package/v4/mini/checks.d.ts +1 -1
- package/v4/mini/checks.js +1 -1
- package/v4/mini/coerce.cjs +19 -0
- package/v4/mini/deep-partial.cjs +19 -0
- package/v4/mini/external.cjs +22 -1
- package/v4/mini/external.d.cts +1 -1
- package/v4/mini/external.d.ts +1 -1
- package/v4/mini/external.js +1 -1
- package/v4/mini/in-out.cjs +19 -0
- package/v4/mini/index.cjs +19 -0
- package/v4/mini/iso.cjs +19 -0
- package/v4/mini/parse.cjs +19 -0
- package/v4/mini/schemas.cjs +42 -4
- package/v4/mini/schemas.d.cts +8 -0
- package/v4/mini/schemas.d.ts +8 -0
- package/v4/mini/schemas.js +19 -2
- package/v4-mini/index.cjs +19 -0
package/v4/core/memoizer.cjs
CHANGED
|
@@ -1,9 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
26
|
exports.$ZodCyclicError = void 0;
|
|
4
27
|
exports.isRecursiveSchema = isRecursiveSchema;
|
|
5
28
|
exports.memoizer = memoizer;
|
|
6
29
|
exports.isBackEdge = isBackEdge;
|
|
30
|
+
const util = __importStar(require("./util.cjs"));
|
|
7
31
|
class $ZodCyclicError extends Error {
|
|
8
32
|
constructor() {
|
|
9
33
|
super(`Cannot parse a reference cycle that closes through a transform`);
|
|
@@ -14,50 +38,168 @@ exports.$ZodCyclicError = $ZodCyclicError;
|
|
|
14
38
|
/** Keyed off the context object every schema in one parse call already shares. */
|
|
15
39
|
const STATE = "~memo";
|
|
16
40
|
const NO_ISSUES = [];
|
|
41
|
+
// a value a cycle can close through; callables count, since z.properties asserts on one
|
|
42
|
+
function isRef(value) {
|
|
43
|
+
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
44
|
+
}
|
|
17
45
|
// Receivers prefix paths in place, so the cache and every hand-out need their own copies.
|
|
18
46
|
function cloneIssues(issues) {
|
|
19
47
|
return issues.map((iss) => (iss.path ? { ...iss, path: iss.path.slice() } : { ...iss }));
|
|
20
48
|
}
|
|
21
49
|
const recursive = /*@__PURE__*/ new WeakMap();
|
|
50
|
+
/** What the walk established, in order of certainty: ordered so the strongest answer among children wins. */
|
|
51
|
+
const NONE = 0;
|
|
52
|
+
const ASSUMED = 1;
|
|
53
|
+
const PROVEN = 2;
|
|
22
54
|
/** Whether this schema's subtree contains a cycle, so one parse can re-enter it. */
|
|
23
|
-
function isRecursive(inst, stack) {
|
|
55
|
+
function isRecursive(inst, stack, resolve) {
|
|
24
56
|
const cached = recursive.get(inst);
|
|
25
57
|
if (cached !== undefined)
|
|
26
|
-
return cached;
|
|
58
|
+
return cached ? PROVEN : NONE;
|
|
27
59
|
// Relative to the walk in progress, so not cached.
|
|
28
60
|
if (stack.has(inst))
|
|
29
|
-
return
|
|
61
|
+
return PROVEN;
|
|
30
62
|
stack.add(inst);
|
|
31
|
-
let result =
|
|
63
|
+
let result = NONE;
|
|
32
64
|
const check = (child) => {
|
|
33
|
-
if (
|
|
34
|
-
|
|
65
|
+
if (result !== PROVEN && child?._zod) {
|
|
66
|
+
const answer = isRecursive(child, stack, resolve);
|
|
67
|
+
if (answer > result)
|
|
68
|
+
result = answer;
|
|
69
|
+
}
|
|
35
70
|
};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// `for...in` skips symbols, so a cycle through a declared symbol key would read as non-recursive
|
|
44
|
-
if (shape)
|
|
45
|
-
for (const key of Reflect.ownKeys(shape))
|
|
46
|
-
check(shape[key]);
|
|
47
|
-
for (const key in def) {
|
|
48
|
-
const value = def[key];
|
|
49
|
-
if (!value || typeof value !== "object")
|
|
71
|
+
// `Reflect.ownKeys` rather than `Object.keys`, so a cycle through a declared symbol key is still seen
|
|
72
|
+
const shape = (sh, spread) => {
|
|
73
|
+
let answer = NONE;
|
|
74
|
+
for (const key of Reflect.ownKeys(sh)) {
|
|
75
|
+
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
76
|
+
// an object resolves its shape by spread, so a key it does not enumerate is never parsed; `z.properties` reads every own key and so keeps them all
|
|
77
|
+
if (spread && !desc.enumerable)
|
|
50
78
|
continue;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
79
|
+
// resolving runs user code, and a factory mints a fresh subtree per read, so an edge the walk can't follow counts as a cycle
|
|
80
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve) : NONE;
|
|
81
|
+
if (child > answer)
|
|
82
|
+
answer = child;
|
|
83
|
+
}
|
|
84
|
+
return answer;
|
|
85
|
+
};
|
|
86
|
+
const merge = (answer) => {
|
|
87
|
+
if (answer > result)
|
|
88
|
+
result = answer;
|
|
89
|
+
};
|
|
90
|
+
const def = inst._zod.def;
|
|
91
|
+
const kind = def.type;
|
|
92
|
+
switch (kind) {
|
|
93
|
+
case "object": {
|
|
94
|
+
const raw = util.rawShape(def);
|
|
95
|
+
// a def with no raw shape answers `shape` from an accessor of its own, and running that can mint a whole fresh subtree
|
|
96
|
+
merge(raw ? shape(raw, true) : ASSUMED);
|
|
97
|
+
check(def.catchall);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
case "properties":
|
|
101
|
+
merge(shape(def.shape, false));
|
|
102
|
+
break;
|
|
103
|
+
case "array":
|
|
104
|
+
check(def.element);
|
|
105
|
+
break;
|
|
106
|
+
case "tuple":
|
|
107
|
+
for (const el of def.items)
|
|
108
|
+
check(el);
|
|
109
|
+
check(def.rest);
|
|
110
|
+
break;
|
|
111
|
+
case "record":
|
|
112
|
+
case "map":
|
|
113
|
+
check(def.keyType);
|
|
114
|
+
check(def.valueType);
|
|
115
|
+
break;
|
|
116
|
+
case "set":
|
|
117
|
+
check(def.valueType);
|
|
118
|
+
break;
|
|
119
|
+
case "union":
|
|
120
|
+
for (const el of def.options)
|
|
121
|
+
check(el);
|
|
122
|
+
break;
|
|
123
|
+
case "intersection":
|
|
124
|
+
check(def.left);
|
|
125
|
+
check(def.right);
|
|
126
|
+
break;
|
|
127
|
+
case "optional":
|
|
128
|
+
case "nullable":
|
|
129
|
+
case "default":
|
|
130
|
+
case "prefault":
|
|
131
|
+
case "catch":
|
|
132
|
+
case "readonly":
|
|
133
|
+
case "nonoptional":
|
|
134
|
+
case "promise":
|
|
135
|
+
case "success":
|
|
136
|
+
check(def.innerType);
|
|
137
|
+
break;
|
|
138
|
+
case "pipe":
|
|
139
|
+
check(def.in);
|
|
140
|
+
check(def.out);
|
|
141
|
+
break;
|
|
142
|
+
case "function":
|
|
143
|
+
check(def.input);
|
|
144
|
+
check(def.output);
|
|
145
|
+
break;
|
|
146
|
+
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
147
|
+
case "lazy": {
|
|
148
|
+
const inner = def._cachedInner ?? (resolve ? inst._zod.innerType : undefined);
|
|
149
|
+
// walked with resolution off: one hop sees past the deferral, and a lazy that yields only another unresolved lazy is generative, so it stops there
|
|
150
|
+
merge(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
// a leaf by choice: `parts` are regex fragments, not data positions
|
|
154
|
+
case "template_literal":
|
|
155
|
+
// leaves
|
|
156
|
+
case "string":
|
|
157
|
+
case "number":
|
|
158
|
+
case "int":
|
|
159
|
+
case "boolean":
|
|
160
|
+
case "bigint":
|
|
161
|
+
case "symbol":
|
|
162
|
+
case "undefined":
|
|
163
|
+
case "null":
|
|
164
|
+
case "void":
|
|
165
|
+
case "never":
|
|
166
|
+
case "any":
|
|
167
|
+
case "unknown":
|
|
168
|
+
case "date":
|
|
169
|
+
case "nan":
|
|
170
|
+
case "enum":
|
|
171
|
+
case "literal":
|
|
172
|
+
case "file":
|
|
173
|
+
case "transform":
|
|
174
|
+
case "custom":
|
|
175
|
+
break;
|
|
176
|
+
default: {
|
|
177
|
+
// a new built-in kind becomes a compile error here
|
|
178
|
+
kind;
|
|
179
|
+
// a user-defined kind can still hold children, and only its author knows where, so fall back to scanning the def — skipping accessors, since reading one can run user code
|
|
180
|
+
for (const key in def) {
|
|
181
|
+
const desc = Object.getOwnPropertyDescriptor(def, key);
|
|
182
|
+
if (!desc || desc.get)
|
|
183
|
+
continue;
|
|
184
|
+
const value = desc.value;
|
|
185
|
+
if (!value || typeof value !== "object")
|
|
186
|
+
continue;
|
|
187
|
+
if (value._zod)
|
|
188
|
+
check(value);
|
|
189
|
+
else if (Array.isArray(value))
|
|
190
|
+
for (const el of value)
|
|
191
|
+
check(el);
|
|
192
|
+
}
|
|
56
193
|
}
|
|
57
194
|
}
|
|
58
195
|
stack.delete(inst);
|
|
59
|
-
|
|
60
|
-
|
|
196
|
+
return settle(inst, result);
|
|
197
|
+
}
|
|
198
|
+
/** An assumed answer must not outlive the resolution that settles it, so only a certain one is cached. */
|
|
199
|
+
function settle(inst, answer) {
|
|
200
|
+
if (answer !== ASSUMED)
|
|
201
|
+
recursive.set(inst, answer === PROVEN);
|
|
202
|
+
return answer;
|
|
61
203
|
}
|
|
62
204
|
/**
|
|
63
205
|
* Whether one parse can re-enter this schema, i.e. its subtree contains a cycle.
|
|
@@ -66,12 +208,13 @@ function isRecursive(inst, stack) {
|
|
|
66
208
|
* generated fast path has no context to key on.
|
|
67
209
|
*/
|
|
68
210
|
function isRecursiveSchema(inst) {
|
|
69
|
-
|
|
211
|
+
// z.compile never parses, so nothing would ever resolve a lazy for it; it runs once and already treats a throw here as recursive
|
|
212
|
+
return isRecursive(inst, new Set(), true) !== NONE;
|
|
70
213
|
}
|
|
71
214
|
function bucketFor(state, inst) {
|
|
72
215
|
let bucket = state.buckets.get(inst);
|
|
73
216
|
if (!bucket) {
|
|
74
|
-
bucket = new
|
|
217
|
+
bucket = new WeakMap();
|
|
75
218
|
state.buckets.set(inst, bucket);
|
|
76
219
|
}
|
|
77
220
|
return bucket;
|
|
@@ -110,7 +253,8 @@ const memo = {
|
|
|
110
253
|
attach(inst) {
|
|
111
254
|
var _a;
|
|
112
255
|
let isRecursiveInst;
|
|
113
|
-
|
|
256
|
+
let rechecked = false;
|
|
257
|
+
// a recursive schema is re-entered many times per parse and its bucket never changes
|
|
114
258
|
let lastCtx;
|
|
115
259
|
let lastBucket;
|
|
116
260
|
// Wraps `parse` in a deferred so it sees the container's final parse. Core's own deferred copies `parse` into `run` when there are no checks, and it ran first, so `run` is patched to match; with checks, `run` reads `parse` dynamically.
|
|
@@ -119,21 +263,26 @@ const memo = {
|
|
|
119
263
|
const base = inst._zod.parse;
|
|
120
264
|
const wrapped = (payload, ctx) => {
|
|
121
265
|
if (isRecursiveInst === undefined) {
|
|
122
|
-
|
|
123
|
-
if (
|
|
266
|
+
const walked = isRecursive(inst, new Set(), false);
|
|
267
|
+
if (walked === NONE) {
|
|
124
268
|
// Nothing here can ever fire, so take it back out.
|
|
125
269
|
inst._zod.parse = base;
|
|
126
270
|
if (inst._zod.run === wrapped)
|
|
127
271
|
inst._zod.run = base;
|
|
128
272
|
return base(payload, ctx);
|
|
129
273
|
}
|
|
274
|
+
// this parse resolves the deferred edges on its own path, so ask once more before latching
|
|
275
|
+
if (walked === PROVEN || rechecked)
|
|
276
|
+
isRecursiveInst = true;
|
|
277
|
+
else
|
|
278
|
+
rechecked = true;
|
|
130
279
|
}
|
|
131
280
|
const input = payload.value;
|
|
132
|
-
if (input
|
|
281
|
+
if (!isRef(input))
|
|
133
282
|
return base(payload, ctx);
|
|
134
283
|
let state = ctx[STATE];
|
|
135
284
|
if (!state) {
|
|
136
|
-
state = { buckets: new
|
|
285
|
+
state = { buckets: new WeakMap(), backEdges: undefined };
|
|
137
286
|
ctx[STATE] = state;
|
|
138
287
|
}
|
|
139
288
|
let bucket;
|
|
@@ -155,7 +304,7 @@ const memo = {
|
|
|
155
304
|
else {
|
|
156
305
|
// Still being parsed: its own checks cover it, so skip them here.
|
|
157
306
|
payload.memo = true;
|
|
158
|
-
state.backEdges ?? (state.backEdges = new
|
|
307
|
+
state.backEdges ?? (state.backEdges = new WeakSet());
|
|
159
308
|
state.backEdges.add(hit.value);
|
|
160
309
|
}
|
|
161
310
|
return payload;
|
|
@@ -191,5 +340,24 @@ function memoizer() {
|
|
|
191
340
|
/** Whether this value is a node a back-edge resolved to before it finished. */
|
|
192
341
|
function isBackEdge(ctx, value) {
|
|
193
342
|
const backEdges = ctx[STATE]?.backEdges;
|
|
194
|
-
return backEdges !== undefined && value
|
|
343
|
+
return backEdges !== undefined && isRef(value) && backEdges.has(value);
|
|
195
344
|
}
|
|
345
|
+
|
|
346
|
+
// seal-cjs-exports
|
|
347
|
+
(function () {
|
|
348
|
+
var keys = Object.getOwnPropertyNames(exports);
|
|
349
|
+
for (var i = 0; i < keys.length; i++) {
|
|
350
|
+
var desc = Object.getOwnPropertyDescriptor(exports, keys[i]);
|
|
351
|
+
if (!desc || !desc.get || !desc.configurable) continue;
|
|
352
|
+
var value;
|
|
353
|
+
try {
|
|
354
|
+
value = desc.get();
|
|
355
|
+
} catch (e) {
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
// a circular require may not have settled this one yet, so leave it live
|
|
359
|
+
if (value === undefined) continue;
|
|
360
|
+
Object.defineProperty(exports, keys[i], { value: value, writable: false, enumerable: desc.enumerable, configurable: false });
|
|
361
|
+
}
|
|
362
|
+
Object.freeze(exports);
|
|
363
|
+
})();
|
package/v4/core/memoizer.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as util from "./util.js";
|
|
1
2
|
export class $ZodCyclicError extends Error {
|
|
2
3
|
constructor() {
|
|
3
4
|
super(`Cannot parse a reference cycle that closes through a transform`);
|
|
@@ -7,50 +8,168 @@ export class $ZodCyclicError extends Error {
|
|
|
7
8
|
/** Keyed off the context object every schema in one parse call already shares. */
|
|
8
9
|
const STATE = "~memo";
|
|
9
10
|
const NO_ISSUES = [];
|
|
11
|
+
// a value a cycle can close through; callables count, since z.properties asserts on one
|
|
12
|
+
function isRef(value) {
|
|
13
|
+
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
14
|
+
}
|
|
10
15
|
// Receivers prefix paths in place, so the cache and every hand-out need their own copies.
|
|
11
16
|
function cloneIssues(issues) {
|
|
12
17
|
return issues.map((iss) => (iss.path ? { ...iss, path: iss.path.slice() } : { ...iss }));
|
|
13
18
|
}
|
|
14
19
|
const recursive = /*@__PURE__*/ new WeakMap();
|
|
20
|
+
/** What the walk established, in order of certainty: ordered so the strongest answer among children wins. */
|
|
21
|
+
const NONE = 0;
|
|
22
|
+
const ASSUMED = 1;
|
|
23
|
+
const PROVEN = 2;
|
|
15
24
|
/** Whether this schema's subtree contains a cycle, so one parse can re-enter it. */
|
|
16
|
-
function isRecursive(inst, stack) {
|
|
25
|
+
function isRecursive(inst, stack, resolve) {
|
|
17
26
|
const cached = recursive.get(inst);
|
|
18
27
|
if (cached !== undefined)
|
|
19
|
-
return cached;
|
|
28
|
+
return cached ? PROVEN : NONE;
|
|
20
29
|
// Relative to the walk in progress, so not cached.
|
|
21
30
|
if (stack.has(inst))
|
|
22
|
-
return
|
|
31
|
+
return PROVEN;
|
|
23
32
|
stack.add(inst);
|
|
24
|
-
let result =
|
|
33
|
+
let result = NONE;
|
|
25
34
|
const check = (child) => {
|
|
26
|
-
if (
|
|
27
|
-
|
|
35
|
+
if (result !== PROVEN && child?._zod) {
|
|
36
|
+
const answer = isRecursive(child, stack, resolve);
|
|
37
|
+
if (answer > result)
|
|
38
|
+
result = answer;
|
|
39
|
+
}
|
|
28
40
|
};
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// `for...in` skips symbols, so a cycle through a declared symbol key would read as non-recursive
|
|
37
|
-
if (shape)
|
|
38
|
-
for (const key of Reflect.ownKeys(shape))
|
|
39
|
-
check(shape[key]);
|
|
40
|
-
for (const key in def) {
|
|
41
|
-
const value = def[key];
|
|
42
|
-
if (!value || typeof value !== "object")
|
|
41
|
+
// `Reflect.ownKeys` rather than `Object.keys`, so a cycle through a declared symbol key is still seen
|
|
42
|
+
const shape = (sh, spread) => {
|
|
43
|
+
let answer = NONE;
|
|
44
|
+
for (const key of Reflect.ownKeys(sh)) {
|
|
45
|
+
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
46
|
+
// an object resolves its shape by spread, so a key it does not enumerate is never parsed; `z.properties` reads every own key and so keeps them all
|
|
47
|
+
if (spread && !desc.enumerable)
|
|
43
48
|
continue;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
// resolving runs user code, and a factory mints a fresh subtree per read, so an edge the walk can't follow counts as a cycle
|
|
50
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve) : NONE;
|
|
51
|
+
if (child > answer)
|
|
52
|
+
answer = child;
|
|
53
|
+
}
|
|
54
|
+
return answer;
|
|
55
|
+
};
|
|
56
|
+
const merge = (answer) => {
|
|
57
|
+
if (answer > result)
|
|
58
|
+
result = answer;
|
|
59
|
+
};
|
|
60
|
+
const def = inst._zod.def;
|
|
61
|
+
const kind = def.type;
|
|
62
|
+
switch (kind) {
|
|
63
|
+
case "object": {
|
|
64
|
+
const raw = util.rawShape(def);
|
|
65
|
+
// a def with no raw shape answers `shape` from an accessor of its own, and running that can mint a whole fresh subtree
|
|
66
|
+
merge(raw ? shape(raw, true) : ASSUMED);
|
|
67
|
+
check(def.catchall);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case "properties":
|
|
71
|
+
merge(shape(def.shape, false));
|
|
72
|
+
break;
|
|
73
|
+
case "array":
|
|
74
|
+
check(def.element);
|
|
75
|
+
break;
|
|
76
|
+
case "tuple":
|
|
77
|
+
for (const el of def.items)
|
|
78
|
+
check(el);
|
|
79
|
+
check(def.rest);
|
|
80
|
+
break;
|
|
81
|
+
case "record":
|
|
82
|
+
case "map":
|
|
83
|
+
check(def.keyType);
|
|
84
|
+
check(def.valueType);
|
|
85
|
+
break;
|
|
86
|
+
case "set":
|
|
87
|
+
check(def.valueType);
|
|
88
|
+
break;
|
|
89
|
+
case "union":
|
|
90
|
+
for (const el of def.options)
|
|
91
|
+
check(el);
|
|
92
|
+
break;
|
|
93
|
+
case "intersection":
|
|
94
|
+
check(def.left);
|
|
95
|
+
check(def.right);
|
|
96
|
+
break;
|
|
97
|
+
case "optional":
|
|
98
|
+
case "nullable":
|
|
99
|
+
case "default":
|
|
100
|
+
case "prefault":
|
|
101
|
+
case "catch":
|
|
102
|
+
case "readonly":
|
|
103
|
+
case "nonoptional":
|
|
104
|
+
case "promise":
|
|
105
|
+
case "success":
|
|
106
|
+
check(def.innerType);
|
|
107
|
+
break;
|
|
108
|
+
case "pipe":
|
|
109
|
+
check(def.in);
|
|
110
|
+
check(def.out);
|
|
111
|
+
break;
|
|
112
|
+
case "function":
|
|
113
|
+
check(def.input);
|
|
114
|
+
check(def.output);
|
|
115
|
+
break;
|
|
116
|
+
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
117
|
+
case "lazy": {
|
|
118
|
+
const inner = def._cachedInner ?? (resolve ? inst._zod.innerType : undefined);
|
|
119
|
+
// walked with resolution off: one hop sees past the deferral, and a lazy that yields only another unresolved lazy is generative, so it stops there
|
|
120
|
+
merge(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
// a leaf by choice: `parts` are regex fragments, not data positions
|
|
124
|
+
case "template_literal":
|
|
125
|
+
// leaves
|
|
126
|
+
case "string":
|
|
127
|
+
case "number":
|
|
128
|
+
case "int":
|
|
129
|
+
case "boolean":
|
|
130
|
+
case "bigint":
|
|
131
|
+
case "symbol":
|
|
132
|
+
case "undefined":
|
|
133
|
+
case "null":
|
|
134
|
+
case "void":
|
|
135
|
+
case "never":
|
|
136
|
+
case "any":
|
|
137
|
+
case "unknown":
|
|
138
|
+
case "date":
|
|
139
|
+
case "nan":
|
|
140
|
+
case "enum":
|
|
141
|
+
case "literal":
|
|
142
|
+
case "file":
|
|
143
|
+
case "transform":
|
|
144
|
+
case "custom":
|
|
145
|
+
break;
|
|
146
|
+
default: {
|
|
147
|
+
// a new built-in kind becomes a compile error here
|
|
148
|
+
kind;
|
|
149
|
+
// a user-defined kind can still hold children, and only its author knows where, so fall back to scanning the def — skipping accessors, since reading one can run user code
|
|
150
|
+
for (const key in def) {
|
|
151
|
+
const desc = Object.getOwnPropertyDescriptor(def, key);
|
|
152
|
+
if (!desc || desc.get)
|
|
153
|
+
continue;
|
|
154
|
+
const value = desc.value;
|
|
155
|
+
if (!value || typeof value !== "object")
|
|
156
|
+
continue;
|
|
157
|
+
if (value._zod)
|
|
158
|
+
check(value);
|
|
159
|
+
else if (Array.isArray(value))
|
|
160
|
+
for (const el of value)
|
|
161
|
+
check(el);
|
|
162
|
+
}
|
|
49
163
|
}
|
|
50
164
|
}
|
|
51
165
|
stack.delete(inst);
|
|
52
|
-
|
|
53
|
-
|
|
166
|
+
return settle(inst, result);
|
|
167
|
+
}
|
|
168
|
+
/** An assumed answer must not outlive the resolution that settles it, so only a certain one is cached. */
|
|
169
|
+
function settle(inst, answer) {
|
|
170
|
+
if (answer !== ASSUMED)
|
|
171
|
+
recursive.set(inst, answer === PROVEN);
|
|
172
|
+
return answer;
|
|
54
173
|
}
|
|
55
174
|
/**
|
|
56
175
|
* Whether one parse can re-enter this schema, i.e. its subtree contains a cycle.
|
|
@@ -59,12 +178,13 @@ function isRecursive(inst, stack) {
|
|
|
59
178
|
* generated fast path has no context to key on.
|
|
60
179
|
*/
|
|
61
180
|
export function isRecursiveSchema(inst) {
|
|
62
|
-
|
|
181
|
+
// z.compile never parses, so nothing would ever resolve a lazy for it; it runs once and already treats a throw here as recursive
|
|
182
|
+
return isRecursive(inst, new Set(), true) !== NONE;
|
|
63
183
|
}
|
|
64
184
|
function bucketFor(state, inst) {
|
|
65
185
|
let bucket = state.buckets.get(inst);
|
|
66
186
|
if (!bucket) {
|
|
67
|
-
bucket = new
|
|
187
|
+
bucket = new WeakMap();
|
|
68
188
|
state.buckets.set(inst, bucket);
|
|
69
189
|
}
|
|
70
190
|
return bucket;
|
|
@@ -103,7 +223,8 @@ const memo = {
|
|
|
103
223
|
attach(inst) {
|
|
104
224
|
var _a;
|
|
105
225
|
let isRecursiveInst;
|
|
106
|
-
|
|
226
|
+
let rechecked = false;
|
|
227
|
+
// a recursive schema is re-entered many times per parse and its bucket never changes
|
|
107
228
|
let lastCtx;
|
|
108
229
|
let lastBucket;
|
|
109
230
|
// Wraps `parse` in a deferred so it sees the container's final parse. Core's own deferred copies `parse` into `run` when there are no checks, and it ran first, so `run` is patched to match; with checks, `run` reads `parse` dynamically.
|
|
@@ -112,21 +233,26 @@ const memo = {
|
|
|
112
233
|
const base = inst._zod.parse;
|
|
113
234
|
const wrapped = (payload, ctx) => {
|
|
114
235
|
if (isRecursiveInst === undefined) {
|
|
115
|
-
|
|
116
|
-
if (
|
|
236
|
+
const walked = isRecursive(inst, new Set(), false);
|
|
237
|
+
if (walked === NONE) {
|
|
117
238
|
// Nothing here can ever fire, so take it back out.
|
|
118
239
|
inst._zod.parse = base;
|
|
119
240
|
if (inst._zod.run === wrapped)
|
|
120
241
|
inst._zod.run = base;
|
|
121
242
|
return base(payload, ctx);
|
|
122
243
|
}
|
|
244
|
+
// this parse resolves the deferred edges on its own path, so ask once more before latching
|
|
245
|
+
if (walked === PROVEN || rechecked)
|
|
246
|
+
isRecursiveInst = true;
|
|
247
|
+
else
|
|
248
|
+
rechecked = true;
|
|
123
249
|
}
|
|
124
250
|
const input = payload.value;
|
|
125
|
-
if (input
|
|
251
|
+
if (!isRef(input))
|
|
126
252
|
return base(payload, ctx);
|
|
127
253
|
let state = ctx[STATE];
|
|
128
254
|
if (!state) {
|
|
129
|
-
state = { buckets: new
|
|
255
|
+
state = { buckets: new WeakMap(), backEdges: undefined };
|
|
130
256
|
ctx[STATE] = state;
|
|
131
257
|
}
|
|
132
258
|
let bucket;
|
|
@@ -148,7 +274,7 @@ const memo = {
|
|
|
148
274
|
else {
|
|
149
275
|
// Still being parsed: its own checks cover it, so skip them here.
|
|
150
276
|
payload.memo = true;
|
|
151
|
-
state.backEdges ?? (state.backEdges = new
|
|
277
|
+
state.backEdges ?? (state.backEdges = new WeakSet());
|
|
152
278
|
state.backEdges.add(hit.value);
|
|
153
279
|
}
|
|
154
280
|
return payload;
|
|
@@ -184,5 +310,5 @@ export function memoizer() {
|
|
|
184
310
|
/** Whether this value is a node a back-edge resolved to before it finished. */
|
|
185
311
|
export function isBackEdge(ctx, value) {
|
|
186
312
|
const backEdges = ctx[STATE]?.backEdges;
|
|
187
|
-
return backEdges !== undefined && value
|
|
313
|
+
return backEdges !== undefined && isRef(value) && backEdges.has(value);
|
|
188
314
|
}
|