summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/internal/validators.mjs
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-02-14 17:38:45 +0100
committerGitHub <noreply@github.com>2023-02-14 17:38:45 +0100
commitd47147fb6ad229b1c039aff9d0959b6e281f4df5 (patch)
tree6e9e790f2b9bc71b5f0c9c7e64b95cae31579d58 /ext/node/polyfills/internal/validators.mjs
parent1d00bbe47e2ca14e2d2151518e02b2324461a065 (diff)
feat(ext/node): embed std/node into the snapshot (#17724)
This commit moves "deno_std/node" in "ext/node" crate. The code is transpiled and snapshotted during the build process. During the first pass a minimal amount of work was done to create the snapshot, a lot of code in "ext/node" depends on presence of "Deno" global. This code will be gradually fixed in the follow up PRs to migrate it to import relevant APIs from "internal:" modules. Currently the code from snapshot is not used in any way, and all Node/npm compatibility still uses code from "https://deno.land/std/node" (or from the location specified by "DENO_NODE_COMPAT_URL"). This will also be handled in a follow up PRs. --------- Co-authored-by: crowlkats <crowlkats@toaxl.com> Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
Diffstat (limited to 'ext/node/polyfills/internal/validators.mjs')
-rw-r--r--ext/node/polyfills/internal/validators.mjs317
1 files changed, 317 insertions, 0 deletions
diff --git a/ext/node/polyfills/internal/validators.mjs b/ext/node/polyfills/internal/validators.mjs
new file mode 100644
index 000000000..bea9e881a
--- /dev/null
+++ b/ext/node/polyfills/internal/validators.mjs
@@ -0,0 +1,317 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+import { codes } from "internal:deno_node/polyfills/internal/error_codes.ts";
+import { hideStackFrames } from "internal:deno_node/polyfills/internal/hide_stack_frames.ts";
+import { isArrayBufferView } from "internal:deno_node/polyfills/internal/util/types.ts";
+import { normalizeEncoding } from "internal:deno_node/polyfills/internal/normalize_encoding.mjs";
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+function isInt32(value) {
+ return value === (value | 0);
+}
+
+/**
+ * @param {unknown} value
+ * @returns {boolean}
+ */
+function isUint32(value) {
+ return value === (value >>> 0);
+}
+
+const octalReg = /^[0-7]+$/;
+const modeDesc = "must be a 32-bit unsigned integer or an octal string";
+
+/**
+ * Parse and validate values that will be converted into mode_t (the S_*
+ * constants). Only valid numbers and octal strings are allowed. They could be
+ * converted to 32-bit unsigned integers or non-negative signed integers in the
+ * C++ land, but any value higher than 0o777 will result in platform-specific
+ * behaviors.
+ *
+ * @param {*} value Values to be validated
+ * @param {string} name Name of the argument
+ * @param {number} [def] If specified, will be returned for invalid values
+ * @returns {number}
+ */
+function parseFileMode(value, name, def) {
+ value ??= def;
+ if (typeof value === "string") {
+ if (!octalReg.test(value)) {
+ throw new codes.ERR_INVALID_ARG_VALUE(name, value, modeDesc);
+ }
+ value = Number.parseInt(value, 8);
+ }
+
+ validateInt32(value, name, 0, 2 ** 32 - 1);
+ return value;
+}
+
+const validateBuffer = hideStackFrames((buffer, name = "buffer") => {
+ if (!isArrayBufferView(buffer)) {
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ name,
+ ["Buffer", "TypedArray", "DataView"],
+ buffer,
+ );
+ }
+});
+
+const validateInteger = hideStackFrames(
+ (
+ value,
+ name,
+ min = Number.MIN_SAFE_INTEGER,
+ max = Number.MAX_SAFE_INTEGER,
+ ) => {
+ if (typeof value !== "number") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "number", value);
+ }
+ if (!Number.isInteger(value)) {
+ throw new codes.ERR_OUT_OF_RANGE(name, "an integer", value);
+ }
+ if (value < min || value > max) {
+ throw new codes.ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
+ }
+ },
+);
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ * @param {{
+ * allowArray?: boolean,
+ * allowFunction?: boolean,
+ * nullable?: boolean
+ * }} [options]
+ */
+const validateObject = hideStackFrames((value, name, options) => {
+ const useDefaultOptions = options == null;
+ const allowArray = useDefaultOptions ? false : options.allowArray;
+ const allowFunction = useDefaultOptions ? false : options.allowFunction;
+ const nullable = useDefaultOptions ? false : options.nullable;
+ if (
+ (!nullable && value === null) ||
+ (!allowArray && Array.isArray(value)) ||
+ (typeof value !== "object" && (
+ !allowFunction || typeof value !== "function"
+ ))
+ ) {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "Object", value);
+ }
+});
+
+const validateInt32 = hideStackFrames(
+ (value, name, min = -2147483648, max = 2147483647) => {
+ // The defaults for min and max correspond to the limits of 32-bit integers.
+ if (!isInt32(value)) {
+ if (typeof value !== "number") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "number", value);
+ }
+
+ if (!Number.isInteger(value)) {
+ throw new codes.ERR_OUT_OF_RANGE(name, "an integer", value);
+ }
+
+ throw new codes.ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
+ }
+
+ if (value < min || value > max) {
+ throw new codes.ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
+ }
+ },
+);
+
+const validateUint32 = hideStackFrames(
+ (value, name, positive) => {
+ if (!isUint32(value)) {
+ if (typeof value !== "number") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "number", value);
+ }
+ if (!Number.isInteger(value)) {
+ throw new codes.ERR_OUT_OF_RANGE(name, "an integer", value);
+ }
+ const min = positive ? 1 : 0;
+ // 2 ** 32 === 4294967296
+ throw new codes.ERR_OUT_OF_RANGE(
+ name,
+ `>= ${min} && < 4294967296`,
+ value,
+ );
+ }
+ if (positive && value === 0) {
+ throw new codes.ERR_OUT_OF_RANGE(name, ">= 1 && < 4294967296", value);
+ }
+ },
+);
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ */
+function validateString(value, name) {
+ if (typeof value !== "string") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "string", value);
+ }
+}
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ */
+function validateNumber(value, name) {
+ if (typeof value !== "number") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "number", value);
+ }
+}
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ */
+function validateBoolean(value, name) {
+ if (typeof value !== "boolean") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "boolean", value);
+ }
+}
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ * @param {unknown[]} oneOf
+ */
+const validateOneOf = hideStackFrames(
+ (value, name, oneOf) => {
+ if (!Array.prototype.includes.call(oneOf, value)) {
+ const allowed = Array.prototype.join.call(
+ Array.prototype.map.call(
+ oneOf,
+ (v) => (typeof v === "string" ? `'${v}'` : String(v)),
+ ),
+ ", ",
+ );
+ const reason = "must be one of: " + allowed;
+
+ throw new codes.ERR_INVALID_ARG_VALUE(name, value, reason);
+ }
+ },
+);
+
+export function validateEncoding(data, encoding) {
+ const normalizedEncoding = normalizeEncoding(encoding);
+ const length = data.length;
+
+ if (normalizedEncoding === "hex" && length % 2 !== 0) {
+ throw new codes.ERR_INVALID_ARG_VALUE(
+ "encoding",
+ encoding,
+ `is invalid for data of length ${length}`,
+ );
+ }
+}
+
+// Check that the port number is not NaN when coerced to a number,
+// is an integer and that it falls within the legal range of port numbers.
+/**
+ * @param {string} name
+ * @returns {number}
+ */
+function validatePort(port, name = "Port", allowZero = true) {
+ if (
+ (typeof port !== "number" && typeof port !== "string") ||
+ (typeof port === "string" &&
+ String.prototype.trim.call(port).length === 0) ||
+ +port !== (+port >>> 0) ||
+ port > 0xFFFF ||
+ (port === 0 && !allowZero)
+ ) {
+ throw new codes.ERR_SOCKET_BAD_PORT(name, port, allowZero);
+ }
+
+ return port;
+}
+
+/**
+ * @param {unknown} signal
+ * @param {string} name
+ */
+const validateAbortSignal = hideStackFrames(
+ (signal, name) => {
+ if (
+ signal !== undefined &&
+ (signal === null ||
+ typeof signal !== "object" ||
+ !("aborted" in signal))
+ ) {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "AbortSignal", signal);
+ }
+ },
+);
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ */
+const validateFunction = hideStackFrames(
+ (value, name) => {
+ if (typeof value !== "function") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "Function", value);
+ }
+ },
+);
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ */
+const validateArray = hideStackFrames(
+ (value, name, minLength = 0) => {
+ if (!Array.isArray(value)) {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "Array", value);
+ }
+ if (value.length < minLength) {
+ const reason = `must be longer than ${minLength}`;
+ throw new codes.ERR_INVALID_ARG_VALUE(name, value, reason);
+ }
+ },
+);
+
+export default {
+ isInt32,
+ isUint32,
+ parseFileMode,
+ validateAbortSignal,
+ validateArray,
+ validateBoolean,
+ validateBuffer,
+ validateFunction,
+ validateInt32,
+ validateInteger,
+ validateNumber,
+ validateObject,
+ validateOneOf,
+ validatePort,
+ validateString,
+ validateUint32,
+};
+export {
+ isInt32,
+ isUint32,
+ parseFileMode,
+ validateAbortSignal,
+ validateArray,
+ validateBoolean,
+ validateBuffer,
+ validateFunction,
+ validateInt32,
+ validateInteger,
+ validateNumber,
+ validateObject,
+ validateOneOf,
+ validatePort,
+ validateString,
+ validateUint32,
+};