Skip to content

Commit

Permalink
feat: Add path, relative, absolute checkers for validating filesystem…
Browse files Browse the repository at this point in the history
… paths
  • Loading branch information
dhoulb committed Dec 16, 2018
1 parent d9bea70 commit b946d60
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 6 deletions.
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -271,6 +271,9 @@ This section lists all types that are available in Blork. Types are strings made
| `kebab`, `slug` | kebab-case strings e.g. URL slugs (non-empty alphanumeric lowercase)
| `train` | Train-Case strings e.g. HTTP-Headers (non-empty with uppercase first letters)
| `identifier` | JavaScript identifier names (string starting with **_**, **$**, or letter)
| `path` | Valid filesystem path (e.g. "abc/def")
| `absolute`, `abs` | Valid absolute path (e.g. "/abc/def" or "C:\abd\def")
| `relative`, `rel` | Valid relative path (e.g. "../abc/def" or "..\abd\def")
| `function`, `func` | Functions (using **instanceof Function**)
| `object`, `obj` | Plain objects (using **typeof && !null** and constructor check)
| `objectlike` | Any object (using **typeof && !null**)
Expand Down
24 changes: 18 additions & 6 deletions lib/checkers/checkers.js
Expand Up @@ -9,13 +9,14 @@ const R_ALPHABETIC = /^[a-zA-Z]+$/;
const R_NUMERIC = /^[0-9]+$/;
const R_UPPER = /^[A-Z]+$/;
const R_LOWER = /^[a-z]+$/;
const R_CAMEL = /^[a-z][a-zA-Z0-9]*$/;
const R_PASCAL = /^[A-Z][a-zA-Z0-9]*$/;
const R_SNAKE = /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/;
const R_SCREAMING = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/;
const R_KEBAB = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
const R_TRAIN = /^[A-Z][a-zA-Z0-9]*(-[A-Z0-9][a-zA-Z0-9]+)*$/;
const R_CAMEL = /^[a-z][a-zA-Z0-9]*$/; // e.g. myVarName
const R_PASCAL = /^[A-Z][a-zA-Z0-9]*$/; // e.g. MyVarName
const R_SNAKE = /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/; // e.g. my_var_name
const R_SCREAMING = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/; // e.g. MY_VAR_NAME
const R_KEBAB = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/; // e.g. my-var-name
const R_TRAIN = /^[A-Z][a-zA-Z0-9]*(-[A-Z0-9][a-zA-Z0-9]+)*$/; // e.g. My-Var-Name
const R_IDENTIFIER = /^[$a-zA-Z_][a-zA-Z0-9_$]*$/;
const R_ABSOLUTE = /^(?:\/|[a-zA-Z]:\\|[/\\]{2}[^/\\]+[/\\/]+[^/\\]+)()/; // e.g. "/" (Unix) "C:\" (Windows) or "//server/file" or "\\server\file" (UNC)

// Checkers.
function isNull(v) { return v === null; }
Expand Down Expand Up @@ -54,6 +55,9 @@ function isScreaming(v) { return typeof v === "string" && R_SCREAMING.test(v); }
function isKebab(v) { return typeof v === "string" && R_KEBAB.test(v); }
function isTrain(v) { return typeof v === "string" && R_TRAIN.test(v); }
function isIdentifier(v) { return typeof v === "string" && R_IDENTIFIER.test(v); }
function isPath(v) { return typeof v === "string" && v.length > 0 && v.length <= 260 && v.indexOf(String.fromCharCode(0)) === -1; } // Total length is no more than 260 (Windows), doesn't contain NUL (Windows and Unix).
function isAbsolute(v) { return isPath(v) && R_ABSOLUTE.test(v); }
function isRelative(v) { return isPath(v) && !R_ABSOLUTE.test(v); }
function isPrimitive(v) { return v === undefined || v === null || typeof v === "boolean" || typeof v === "string" || Number.isFinite(v); }
function isFunction(v) { return typeof v === "function"; }
function isObject(v) { return typeof v === "object" && v !== null; }
Expand Down Expand Up @@ -117,6 +121,9 @@ isScreaming.desc = "SCREAMING_SNAKE_CASE string";
isKebab.desc = "kebab-case string";
isTrain.desc = "Camel-Kebab-Case string";
isIdentifier.desc = "valid JavaScript identifier";
isPath.desc = "valid path";
isAbsolute.desc = "absolute path";
isRelative.desc = "relative path";
isFunction.desc = "function";
isObject.desc = "object";
isPlainObject.desc = "plain object";
Expand Down Expand Up @@ -206,6 +213,11 @@ const checkers = {
"slug": isKebab,
"train": isTrain,
"identifier": isIdentifier,
"path": isPath,
"abs": isAbsolute,
"absolute": isAbsolute,
"rel": isRelative,
"relative": isRelative,

// Objects.
"function": isFunction,
Expand Down
10 changes: 10 additions & 0 deletions test/checkers/checkers.test.js
Expand Up @@ -77,6 +77,11 @@ describe("checkers", () => {
expect(mockCheck("my-var", "slug")).toBe(undefined);
expect(mockCheck("My-Var", "train")).toBe(undefined);
expect(mockCheck("$name", "identifier")).toBe(undefined);
expect(mockCheck("abc/def", "path")).toBe(undefined);
expect(mockCheck("..\\abc\\def", "rel")).toBe(undefined);
expect(mockCheck("../abc/def", "relative")).toBe(undefined);
expect(mockCheck("/abc/def", "abs")).toBe(undefined);
expect(mockCheck("C:\\abc\\def", "absolute")).toBe(undefined);

// Objects.
expect(mockCheck(function() {}, "function")).toBe(undefined);
Expand Down Expand Up @@ -195,6 +200,11 @@ describe("checkers", () => {
expect(() => mockCheck("my-VAR", "slug")).toThrow(TypeError);
expect(() => mockCheck("my-var", "train")).toThrow(TypeError);
expect(() => mockCheck("*name", "identifier")).toThrow(TypeError);
expect(() => mockCheck(String.fromCharCode(0), "path")).toThrow(TypeError);
expect(() => mockCheck("/abc/def", "rel")).toThrow(TypeError);
expect(() => mockCheck("C:\\abc\\def", "relative")).toThrow(TypeError);
expect(() => mockCheck("../abc/def", "abs")).toThrow(TypeError);
expect(() => mockCheck("..\\abc\\def", "absolute")).toThrow(TypeError);

// Objects.
expect(() => mockCheck({}, "function")).toThrow(TypeError);
Expand Down

0 comments on commit b946d60

Please sign in to comment.