@scalar/validation 0.6.5 → 0.6.6

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @scalar/validation
2
2
 
3
+ ## 0.6.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [#10417](https://github.com/scalar/scalar/pull/10417): Reduce union scoring overhead for literals, arrays, records, and missing optional values while preserving branch selection.
8
+
3
9
  ## 0.6.5
4
10
 
5
11
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"coerce.d.ts","sourceRoot":"","sources":["../src/coerce.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AA6CrC;;;;;;;;;GASG;AACH,KAAK,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAqWxC;;;;;;;;;;;;;GAaG;AACH,KAAK,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;AAE1E;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,MAAM,EACrC,QAAQ,CAAC,EACT,OAAO,OAAO,EACd,QAAO,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAiB,EAC5D,YAAW,SAAyB,KACnC,UAAU,CAAC,CAAC,CAAyF,CAAA"}
1
+ {"version":3,"file":"coerce.d.ts","sourceRoot":"","sources":["../src/coerce.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AA6CrC;;;;;;;;;GASG;AACH,KAAK,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AA+WxC;;;;;;;;;;;;;GAaG;AACH,KAAK,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;AAE1E;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,MAAM,EACrC,QAAQ,CAAC,EACT,OAAO,OAAO,EACd,QAAO,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAiB,EAC5D,YAAW,SAAyB,KACnC,UAAU,CAAC,CAAC,CAAyF,CAAA"}
package/dist/coerce.js CHANGED
@@ -98,13 +98,30 @@ const isDiscriminatorProperty = (schema) => {
98
98
  * descent into child values.
99
99
  */
100
100
  const scoreUnion = (schema, value, lazyCache, scoringCache = new WeakMap(), valueDepth = 0, lazyDepth = 0) => {
101
+ // These scores do not descend into the value, so they cannot encounter a cycle.
102
+ // In particular, literals are common in discriminator and enum unions and do
103
+ // not need a separate validation traversal or its cache allocation.
104
+ if (schema.type === 'literal') {
105
+ // Keep strict equality in sync with the literal branch of validateInner in validate.ts.
106
+ return value === schema.value ? 1 : 0;
107
+ }
108
+ if (schema.type === 'array') {
109
+ return Array.isArray(value) ? 1 : 0;
110
+ }
111
+ if (schema.type === 'record') {
112
+ // TODO: implement smarter scoring for records
113
+ return isObject(value) ? 1 : 0;
114
+ }
115
+ if (schema.type === 'optional' && value === undefined) {
116
+ return 1;
117
+ }
118
+ const trackable = isObject(value);
101
119
  // Short-circuit on cycles: this exact (value, schema) pair is already being
102
120
  // scored higher up the call stack. The enclosing call's score subsumes any
103
121
  // contribution we could compute here, so return a neutral positive score.
104
- if (isObject(value) && scoringCache.get(value)?.has(schema)) {
122
+ if (trackable && scoringCache.get(value)?.has(schema)) {
105
123
  return 1;
106
124
  }
107
- const trackable = isObject(value);
108
125
  if (trackable) {
109
126
  const schemas = scoringCache.get(value) ?? new Set();
110
127
  schemas.add(schema);
@@ -112,7 +129,7 @@ const scoreUnion = (schema, value, lazyCache, scoringCache = new WeakMap(), valu
112
129
  }
113
130
  try {
114
131
  if (schema.type === 'object') {
115
- if (!isObject(value)) {
132
+ if (!trackable) {
116
133
  return 0;
117
134
  }
118
135
  const keys = Object.keys(schema.properties);
@@ -148,16 +165,8 @@ const scoreUnion = (schema, value, lazyCache, scoringCache = new WeakMap(), valu
148
165
  return acc + (base > 0 ? base : 1);
149
166
  }, 0);
150
167
  }
151
- if (schema.type === 'array') {
152
- // Score 1 if value is an array, otherwise 0
153
- return Array.isArray(value) ? 1 : 0;
154
- }
155
- if (schema.type === 'record') {
156
- // TODO: implement smarter scoring for records (just a placeholder for now)
157
- return isObject(value) ? 1 : 0;
158
- }
159
168
  if (schema.type === 'optional') {
160
- return value === undefined ? 1 : scoreUnion(schema.schema, value, lazyCache, scoringCache, valueDepth, lazyDepth);
169
+ return scoreUnion(schema.schema, value, lazyCache, scoringCache, valueDepth, lazyDepth);
161
170
  }
162
171
  if (schema.type === 'union') {
163
172
  // For a union, use the highest score among all sub-schemas
package/package.json CHANGED
@@ -15,7 +15,7 @@
15
15
  "coerce",
16
16
  "scalar"
17
17
  ],
18
- "version": "0.6.5",
18
+ "version": "0.6.6",
19
19
  "engines": {
20
20
  "node": ">=20"
21
21
  },