Compare commits

...

4 Commits

Author SHA1 Message Date
Jarred Sumner
0be86b52f2 Update validators.ts 2025-04-14 20:32:30 -07:00
Jarred Sumner
7675f61c81 fix 2025-04-14 19:45:10 -07:00
Jarred Sumner
726cc9b613 Merge branch 'main' into jarred/faster-validators 2025-04-14 19:31:36 -07:00
Jarred Sumner
127a9e1bd7 Make validators faster 2025-04-13 05:40:20 -07:00
2 changed files with 55 additions and 22 deletions

View File

@@ -674,7 +674,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateObject, (JSC::JSGlobalObject * globa
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, callFrame->argument(1), "object"_s, value);
}
if (!value.isObject() || value.asCell()->type() != FinalObjectType) {
if (!JSC::jsTypeofIsObject(globalObject, value)) {
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, callFrame->argument(1), "object"_s, value);
}
@@ -687,7 +687,7 @@ JSC::EncodedJSValue V::validateObject(JSC::ThrowScope& scope, JSC::JSGlobalObjec
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "object"_s, value);
}
if (!value.isObject() || value.asCell()->type() != FinalObjectType) {
if (!JSC::jsTypeofIsObject(globalObject, value)) {
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "object"_s, value);
}

View File

@@ -1,19 +1,16 @@
const { hideFromStack } = require("internal/shared");
const RegExpPrototypeExec = RegExp.prototype.exec;
const ArrayPrototypeIncludes = Array.prototype.includes;
const ArrayPrototypeJoin = Array.prototype.join;
const ArrayPrototypeMap = Array.prototype.map;
const ArrayIsArray = Array.isArray;
const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;
let tokenRegExp: RegExp | undefined;
/**
* Verifies that the given val is a valid HTTP token
* per the rules defined in RFC 7230
* See https://tools.ietf.org/html/rfc7230#section-3.2.6
*/
function checkIsHttpToken(val) {
return RegExpPrototypeExec.$call(tokenRegExp, val) !== null;
return RegExpPrototypeExec.$call((tokenRegExp ??= /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/), val) !== null;
}
/*
@@ -24,9 +21,12 @@ function checkIsHttpToken(val) {
(not necessarily a valid URI reference) followed by zero or more
link-params separated by semicolons.
*/
const linkValueRegExp = /^(?:<[^>]*>)(?:\s*;\s*[^;"\s]+(?:=(")?[^;"\s]*\1)?)*$/;
let linkValueRegExp: RegExp | undefined;
function validateLinkHeaderFormat(value, name) {
if (typeof value === "undefined" || !RegExpPrototypeExec.$call(linkValueRegExp, value)) {
if (
typeof value === "undefined" ||
!RegExpPrototypeExec.$call((linkValueRegExp ??= /^(?:<[^>]*>)(?:\s*;\s*[^;"\s]+(?:=(")?[^;"\s]*\1)?)*$/), value)
) {
throw $ERR_INVALID_ARG_VALUE(
name,
value,
@@ -39,7 +39,7 @@ function validateLinkHeaderValue(hints) {
if (typeof hints === "string") {
validateLinkHeaderFormat(hints, "hints");
return hints;
} else if (ArrayIsArray(hints)) {
} else if ($isArray(hints)) {
const hintsLength = hints.length;
let result = "";
@@ -68,31 +68,56 @@ function validateLinkHeaderValue(hints) {
}
hideFromStack(validateLinkHeaderValue);
// We want to let the JIT remove the most trivial checks.
const validateNumberInternal = $newCppFunction("NodeValidator.cpp", "jsFunction_validateNumber", 0);
const validateStringInternal = $newCppFunction("NodeValidator.cpp", "jsFunction_validateString", 0);
const validateFunctionInternal = $newCppFunction("NodeValidator.cpp", "jsFunction_validateFunction", 0);
const validateBooleanInternal = $newCppFunction("NodeValidator.cpp", "jsFunction_validateBoolean", 0);
const validateArrayInternal = $newCppFunction("NodeValidator.cpp", "jsFunction_validateArray", 0);
export default {
/** (value, name) */
validateObject: $newCppFunction("NodeValidator.cpp", "jsFunction_validateObject", 2),
validateLinkHeaderValue: validateLinkHeaderValue,
checkIsHttpToken: checkIsHttpToken,
/** `(value, name, min, max)` */
validateInteger: $newCppFunction("NodeValidator.cpp", "jsFunction_validateInteger", 0),
/** `(value, name, min, max)` */
validateNumber: $newCppFunction("NodeValidator.cpp", "jsFunction_validateNumber", 0),
validateNumber: function validateNumber(value, name, min, max) {
if (typeof value !== "number") {
return validateNumberInternal.$apply(this, arguments);
}
},
/** `(value, name)` */
validateString: $newCppFunction("NodeValidator.cpp", "jsFunction_validateString", 0),
validateString: function validateString(value, name) {
if (typeof value !== "string") {
return validateStringInternal.$apply(this, arguments);
}
},
/** `(number, name)` */
validateFiniteNumber: $newCppFunction("NodeValidator.cpp", "jsFunction_validateFiniteNumber", 0),
/** `(number, name, lower, upper, def)` */
checkRangesOrGetDefault: $newCppFunction("NodeValidator.cpp", "jsFunction_checkRangesOrGetDefault", 0),
/** `(value, name)` */
validateFunction: $newCppFunction("NodeValidator.cpp", "jsFunction_validateFunction", 0),
validateFunction: function validateFunction(value, name) {
if (!$isCallable(value)) {
return validateFunctionInternal.$apply(this, arguments);
}
},
/** `(value, name)` */
validateBoolean: $newCppFunction("NodeValidator.cpp", "jsFunction_validateBoolean", 0),
/** `(port, name = 'Port', allowZero = true)` */
validateBoolean: function validateBoolean(value, name) {
if (typeof value !== "boolean") {
return validateBooleanInternal.$apply(this, arguments);
}
},
validatePort: $newCppFunction("NodeValidator.cpp", "jsFunction_validatePort", 0),
/** `(signal, name)` */
validateAbortSignal: $newCppFunction("NodeValidator.cpp", "jsFunction_validateAbortSignal", 0),
/** `(value, name, minLength = 0)` */
validateArray: $newCppFunction("NodeValidator.cpp", "jsFunction_validateArray", 0),
validateArray: function validateArray(value, name, minLength) {
if (!$isArray(value) || (typeof minLength === "number" && value.length < minLength)) {
return validateArrayInternal.$apply(this, arguments);
}
},
/** `(value, name, min = -2147483648, max = 2147483647)` */
validateInt32: $newCppFunction("NodeValidator.cpp", "jsFunction_validateInt32", 0),
/** `(value, name, positive = false)` */
@@ -101,12 +126,20 @@ export default {
validateSignalName: $newCppFunction("NodeValidator.cpp", "jsFunction_validateSignalName", 0),
/** `(data, encoding)` */
validateEncoding: $newCppFunction("NodeValidator.cpp", "jsFunction_validateEncoding", 0),
// ** UNUSED **
/** `(value, name)` */
validatePlainFunction: $newCppFunction("NodeValidator.cpp", "jsFunction_validatePlainFunction", 0),
/** `(value, name)` */
validateUndefined: $newCppFunction("NodeValidator.cpp", "jsFunction_validateUndefined", 0),
// validatePlainFunction: $newCppFunction("NodeValidator.cpp", "jsFunction_validatePlainFunction", 0),
// /** `(value, name)` */
// validateUndefined: function validateUndefined(value, name) {
// if (typeof value !== "undefined") {
// return validateUndefinedInternal.$apply(this, arguments);
// }
// },
/** `(buffer, name = 'buffer')` */
validateBuffer: $newCppFunction("NodeValidator.cpp", "jsFunction_validateBuffer", 0),
/** `(value, name, oneOf)` */
validateOneOf: $newCppFunction("NodeValidator.cpp", "jsFunction_validateOneOf", 0),
validateLinkHeaderValue: validateLinkHeaderValue,
checkIsHttpToken: checkIsHttpToken,
};