Files
deno-valideno/validators/string.ts
2020-12-05 23:00:08 +01:00

168 lines
5.0 KiB
TypeScript

import { Validator, Args } from "../mod.ts";
export function isString(): Validator {
return {
type: "isString",
check: (value: any) => {
if (value === null || value === undefined) return;
if (typeof value !== "string" && !(value instanceof String)) {
return {};
}
},
message: (value: any, args?: Args) => {
return `This value has to be a string.`;
},
};
}
/**
* Thanks to https://gist.github.com/dperini/729294
* Data URL https://gist.github.com/bgrins/6194623
*
* @param param Options
*/
export function isUrl(
{
protocols = ["http", "https"],
allowDataUrl = false,
allowUrl = true,
allowLocal = false,
allowIp = true,
allowDomain = true,
allowBasicAuth = false,
allowPort = true,
allowResourcePath = true,
}: {
protocols?: string[] | null;
allowDataUrl?: boolean;
allowUrl?: boolean;
allowLocal?: boolean;
allowIp?: boolean;
allowDomain?: boolean;
allowBasicAuth?: boolean;
allowPort?: boolean;
allowResourcePath?: boolean;
} = {},
): Validator {
return {
type: "isUrl",
extends: [isString()],
check: (value: any) => {
if (value === null || value === undefined) return;
if (allowUrl) {
let regex = "^";
// protocol identifier (optional)
// short syntax // still required
if (protocols) {
regex += `(?:(?:(?:${protocols.join("|")}):)?\\/\\/)`;
} else {
regex += `(?:(?:(?:[a-z]+):)?\/\/)`;
}
// user:pass BasicAuth (optional)
if (allowBasicAuth) {
regex += "(?:\\S+(?::\\S*)?@)?";
}
regex += "(?:"; // [hostname] start
if (allowIp && !allowLocal) {
regex += "(?!(?:10|127)(?:\\.\\d{1,3}){3})" +
"(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" +
"(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})";
}
if (allowIp) {
regex += "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
"(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
"(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))";
}
if (allowIp || allowDomain) {
regex += "|"; // [hostname] ip end / domain start
}
if (allowDomain) {
// host & domain names, may end with dot
// can be replaced by a shortest alternative
// (?![-_])(?:[-\\w\\u00a1-\\uffff]{0,63}[^-_]\\.)+
regex += "(?:" +
"(?:" +
"[a-z0-9\\u00a1-\\uffff]" +
"[a-z0-9\\u00a1-\\uffff_-]{0,62}" +
")?" +
"[a-z0-9\\u00a1-\\uffff]\\." +
")+" +
// TLD identifier name, may end with dot
"(?:[a-z\\u00a1-\\uffff]{2,}\\.?)";
}
regex += ")"; // [hostname] end
if (allowPort) {
// port number (optional)
regex += "(?::\\d{2,5})?";
}
if (allowResourcePath) {
// resource path (optional)
regex += "(?:[/?#]\\S*)?";
}
regex += "$";
if (value.match(new RegExp(regex, "i"))) {
return;
}
}
if (allowDataUrl) {
const regex =
/^\s*data:([a-z]+\/[a-z]+(;[a-z\-]+=[a-z\-]+)?)?(;base64)?,[a-z0-9!$&',()*+;=\-._~:@\/?%\s]*\s*$/i;
if (value.match(regex)) {
return;
}
}
return {};
},
message: (value: any, args?: Args) => {
return `This value is not a valid URL.`;
},
};
}
/**
* https://stackoverflow.com/questions/201323/how-to-validate-an-email-address-using-a-regular-expression
*/
export function isEmail(): Validator {
return {
type: "isEmail",
extends: [isString()],
convert: (value: any) => {
if (value === true) {
return "true";
} else if (value === false) {
return "false";
} else if (typeof value === "number") {
return value.toString();
}
},
check: (value: any) => {
if (value === null || value === undefined) return;
const regex =
/^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i;
if (value.match(regex)) {
return;
}
return {};
},
message: (value: any, args?: Args) => {
return `This value has to be an email address.`;
},
};
}
export function fulfillsRegex({ regex }: { regex: RegExp }): Validator {
return {
type: "fulfillsRegex",
extends: [isString()],
check: (value: any) => {
if (value === null || value === undefined) return;
if (!value.match(regex)) {
return {};
}
},
message: (value: any, args?: Args) => {
return `This value has to fulfill the regex ${regex}.`;
},
};
}