TypeScript!

This commit is contained in:
Zaid Abdulla committed 2019-02-20 03:36:52 -08:00
1 parent ee8c43747e
commit 5d3c81cb23
105 files changed
+12054 -1901

No files matched your search

@@ -1,20 +1,27 @@
"use strict";
import pass from "./validators/pass";
import test from "./validators/test";
import { PermissionSet } from "../types";
const validators = { pass, test };
export default class Authorizer {
constructor(permissionSets) {
private permissionSets: PermissionSet[];
private validatorCache: WeakMap<
object,
(mutationType, mutation, any) => boolean
>;
private hasAccessCache: Map<string, boolean>;
public constructor(permissionSets) {
this.permissionSets = permissionSets;
this.validatorCache = new WeakMap();
this.hasAccessCache = {};
this.hasAccessCache = new Map();
}
hasAccess(resourceType, access) {
public hasAccess(resourceType, access): boolean {
const cacheKey = `${resourceType}-${access}`;
if (cacheKey in this.hasAccessCache) return this.hasAccessCache[cacheKey];
if (this.hasAccessCache.has(cacheKey))
return this.hasAccessCache.get(cacheKey);
let has = false;
for (const permissionSet of this.permissionSets) {
@@ -28,11 +35,14 @@ export default class Authorizer {
}
}
this.hasAccessCache[cacheKey] = has;
this.hasAccessCache.set(cacheKey, has);
return has;
}
getValidator(resourceType, resource) {
public getValidator(
resourceType,
resource
): (mutationType: string, mutation: any, args: any) => boolean {
if (this.validatorCache.has(resource))
return this.validatorCache.get(resource);
@@ -53,7 +63,11 @@ export default class Authorizer {
}
}
const validator = (mutationType, mutation, any) => {
const validator = (
mutationType: string,
mutation: any,
any: any
): boolean => {
let valid = false;
for (const [k, v] of Object.entries(funcs)) {
if (v) {
@@ -1,8 +1,9 @@
"use strict";
import { map, parseLikePattern } from "./expression-parser";
import { Expression } from "../types";
function or(cnf1, cnf2) {
type CNF = number[][];
function or(cnf1: CNF, cnf2: CNF): CNF {
if (cnf1.length === 0) return cnf2;
else if (cnf2.length === 0) return cnf1;
@@ -19,7 +20,30 @@ function or(cnf1, cnf2) {
return res;
}
export function booleanCnf(exp) {
function likePatternIncludes(pat1, pat2, idx1 = 0, idx2 = 0): boolean {
while (idx1 < pat1.length && idx2 < pat2.length) {
if (pat1[idx1] === "\\%") {
for (let i = idx2; i <= pat2.length; ++i)
if (likePatternIncludes(pat1, pat2, idx1 + 1, i)) return true;
return false;
} else if (pat2[idx2] === "\\%") {
if (pat1[idx1] !== "\\%") return false;
} else if (pat1[idx1] === "\\_") {
// Ignore
} else if (pat2[idx2] === "\\_") {
return false;
} else if (pat2[idx2] !== pat1[idx1]) {
return false;
}
++idx1;
++idx2;
}
if (idx1 === pat1.length && idx2 === pat2.length) return true;
return false;
}
export function booleanCnf(exp: Expression): { vars: number; clauses: CNF } {
const ranges = new Map();
const likePatterns = new Map();
map(exp, e => {
@@ -51,15 +75,20 @@ export function booleanCnf(exp) {
});
for (const [k, v] of ranges) {
if (k.endsWith(":number"))
ranges.set(k, Array.from(v).sort((a, b) => a - b));
else ranges.set(k, Array.from(v).sort());
if (k.endsWith(":number")) {
ranges.set(
k,
Array.from(v as number[]).sort((a: number, b: number) => a - b)
);
} else {
ranges.set(k, Array.from(v).sort());
}
}
const expressions = new Map();
const mutuallyExclusive = new Map();
const expressions: Map<string, number> = new Map();
const mutuallyExclusive: Map<string, Set<number>> = new Map();
function getVariable(lhs, op, rhs = "") {
function getVariable(lhs, op, rhs = ""): number {
const key = `${lhs}:${op}:${rhs}`;
let f = expressions.get(key);
if (!f) {
@@ -72,7 +101,13 @@ export function booleanCnf(exp) {
return f;
}
function getComparisonVariables(lhs, from, fromInclusive, to, toInclusive) {
function getComparisonVariables(
lhs,
from,
fromInclusive,
to,
toInclusive
): number[] {
const type = from != null ? typeof from : typeof to;
const range = ranges.get(`${lhs}:${type}`);
const vars = [];
@@ -109,7 +144,7 @@ export function booleanCnf(exp) {
});
}
function getLikeVariables(lhs, pat, esc) {
function getLikeVariables(lhs, pat, esc): number[] {
const vars = [];
const pats = likePatterns.get(lhs);
pat = pats.get(`${esc || ""}:${pat}`);
@@ -125,7 +160,11 @@ export function booleanCnf(exp) {
});
}
const comparisonOperators = {
interface ComparisonOperators {
[name: string]: (v: string) => [string, boolean, string, boolean];
}
const comparisonOperators: ComparisonOperators = {
"=": v => [v, true, v, true],
">": v => [v, false, null, null],
">=": v => [v, true, null, null],
@@ -133,7 +172,7 @@ export function booleanCnf(exp) {
"<=": v => [null, null, v, true]
};
function recursive(clause, negate) {
function recursive(clause, negate): CNF {
let op = clause[0];
if ((op === "AND" && !negate) || (op === "OR" && negate)) {
@@ -218,33 +257,10 @@ export function booleanCnf(exp) {
const cnf = recursive(exp, false);
for (const m of mutuallyExclusive.values()) {
const ar = Array.from(m);
const ar: number[] = Array.from(m);
for (let i = 0; i < ar.length; ++i)
for (let j = i + 1; j < ar.length; ++j) cnf.push([0 - ar[i], 0 - ar[j]]);
}
return { vars: expressions.size, clauses: cnf };
}
function likePatternIncludes(pat1, pat2, idx1 = 0, idx2 = 0) {
while (idx1 < pat1.length && idx2 < pat2.length) {
if (pat1[idx1] === "\\%") {
for (let i = idx2; i <= pat2.length; ++i)
if (likePatternIncludes(pat1, pat2, idx1 + 1, i)) return true;
return false;
} else if (pat2[idx2] === "\\%") {
if (pat1[idx1] !== "\\%") return false;
} else if (pat1[idx1] === "\\_") {
// Ignore
} else if (pat2[idx2] === "\\_") {
return false;
} else if (pat2[idx2] !== pat1[idx1]) {
return false;
}
++idx1;
++idx2;
}
if (idx1 === pat1.length && idx2 === pat2.length) return true;
return false;
}
@@ -1,9 +1,8 @@
"use strict";
import parsimmon from "parsimmon";
import * as parsimmon from "parsimmon";
import { Expression } from "../types";
// Turn escaped characters into real ones (e.g. "\\n" becomes "\n").
function interpretEscapes(str) {
function interpretEscapes(str): string {
const escapes = {
b: "\b",
f: "\f",
@@ -22,7 +21,7 @@ function interpretEscapes(str) {
});
}
export function map(exp, callback) {
export function map(exp, callback): Expression {
if (!Array.isArray(exp)) return callback(exp);
let clone;
@@ -37,7 +36,7 @@ export function map(exp, callback) {
return callback(clone || exp);
}
function binaryLeft(operatorsParser, nextParser) {
function binaryLeft(operatorsParser, nextParser): parsimmon.Parser<{}> {
return parsimmon.seqMap(
nextParser,
parsimmon.seq(operatorsParser, nextParser).many(),
@@ -257,7 +256,7 @@ const lang = parsimmon.createLanguage({
);
},
Expression: function(r) {
function unary(operatorsParser, nextParser) {
function unary(operatorsParser, nextParser): parsimmon.Parser<{}> {
return parsimmon.seq(operatorsParser, nextParser).or(nextParser);
}
@@ -271,12 +270,12 @@ const lang = parsimmon.createLanguage({
}
});
export function parse(str) {
export function parse(str): Expression {
if (!str) return null;
return lang.Expression.tryParse(str);
}
export function stringify(exp, level = 0) {
export function stringify(exp, level = 0): string {
if (!Array.isArray(exp)) return JSON.stringify(exp);
const opLevels = {
@@ -302,7 +301,7 @@ export function stringify(exp, level = 0) {
const op = exp[0].toUpperCase();
function wrap(e) {
function wrap(e): string {
if (opLevels[op] <= level) return `(${e})`;
else return e;
}
@@ -360,7 +359,7 @@ export function stringify(exp, level = 0) {
}
}
export function parseLikePattern(pat, esc) {
export function parseLikePattern(pat, esc): string[] {
const chars = pat.split("");
for (let i = 0; i < chars.length; ++i) {
@@ -1,15 +1,14 @@
"use strict";
import { map, parseLikePattern } from "./expression-parser";
import { booleanCnf } from "./expression-cnf";
import { naiveDpll } from "./sat-solver";
import { Expression } from "../types";
const isArray = Array.isArray;
const regExpCache = new WeakMap();
const REDUCE_SKIP = {};
function reduce(exp, callback) {
function reduce(exp, callback): Expression {
let loop = true;
while (loop) {
loop = false;
@@ -26,8 +25,45 @@ function reduce(exp, callback) {
return exp;
}
export function evaluate(exp, obj, now, cb) {
function getRegExp(pat, esc) {
export function likePatternToRegExp(pat, esc = "", flags = ""): RegExp {
const convChars = {
"-": "\\-",
"/": "\\/",
"\\": "\\/",
"^": "\\^",
$: "\\$",
"*": "\\*",
"+": "\\+",
"?": "\\?",
".": "\\.",
"(": "\\(",
")": "\\)",
"|": "\\|",
"[": "\\[",
"]": "\\]",
"{": "\\{",
"}": "\\}",
"\\%": ".*",
"\\_": "."
};
let chars = parseLikePattern(pat, esc);
if (!chars.length) return new RegExp("^$", flags);
chars = chars.map(c => convChars[c] || c);
chars[0] = chars[0] === ".*" ? "" : "^" + chars[0];
const l = chars.length - 1;
chars[l] = [".*", ""].includes(chars[l]) ? "" : chars[l] + "$";
return new RegExp(chars.join(""), flags);
}
export function evaluate(
exp,
obj,
now: number,
cb?: Function
): string | number | boolean | null;
export function evaluate(exp, obj?, now?: number, cb?: Function): Expression;
export function evaluate(exp, obj?, now?: number, cb?: Function): Expression {
function getRegExp(pat, esc): RegExp {
const k = `${esc || ""}:${pat}`;
let c = regExpCache.get(exp);
if (!c) regExpCache.set(exp, (c = {}));
@@ -162,11 +198,11 @@ export function evaluate(exp, obj, now, cb) {
});
}
export function and(exp1, exp2) {
export function and(exp1, exp2): Expression {
if (!isArray(exp1)) return exp1 ? exp2 : exp1;
if (!isArray(exp2)) return exp2 ? exp1 : exp2;
let res = ["AND"];
let res: Expression = ["AND"];
if (exp1[0] === "AND") res = res.concat(exp1.slice(1));
else res.push(exp1);
@@ -177,11 +213,11 @@ export function and(exp1, exp2) {
return res;
}
export function or(exp1, exp2) {
export function or(exp1, exp2): Expression {
if (!isArray(exp1)) return exp1 ? exp1 : exp2;
if (!isArray(exp2)) return exp2 ? exp2 : exp1;
let res = ["OR"];
let res: Expression = ["OR"];
if (exp1[0] === "OR") res = res.concat(exp1.slice(1));
else res.push(exp1);
@@ -192,49 +228,19 @@ export function or(exp1, exp2) {
return res;
}
export function not(exp) {
export function not(exp): Expression {
if (isArray(exp) && exp[0] === "NOT") return exp[1];
return ["NOT", exp];
}
export function subset(exp1, exp2) {
export function subset(exp1, exp2): boolean {
const e = evaluate(["NOT", ["OR", ["NOT", exp1], exp2]]);
if (!isArray(e)) return !e;
const { vars, clauses } = booleanCnf(e);
return !naiveDpll(clauses, vars);
}
export function likePatternToRegExp(pat, esc = "", flags = "") {
const convChars = {
"-": "\\-",
"/": "\\/",
"\\": "\\/",
"^": "\\^",
$: "\\$",
"*": "\\*",
"+": "\\+",
"?": "\\?",
".": "\\.",
"(": "\\(",
")": "\\)",
"|": "\\|",
"[": "\\[",
"]": "\\]",
"{": "\\{",
"}": "\\}",
"\\%": ".*",
"\\_": "."
};
let chars = parseLikePattern(pat, esc);
if (!chars.length) return new RegExp("^$", flags);
chars = chars.map(c => convChars[c] || c);
chars[0] = chars[0] === ".*" ? "" : "^" + chars[0];
const l = chars.length - 1;
chars[l] = [".*", ""].includes(chars[l]) ? "" : chars[l] + "$";
return new RegExp(chars.join(""), flags);
}
export function extractParams(exp) {
export function extractParams(exp): string[] {
const params = new Set();
map(exp, e => {
if (isArray(e) && e[0] === "PARAM") params.add(e[1]);
@@ -1,10 +1,8 @@
"use strict";
let cache1 = new Map();
let cache2 = new Map();
const keys = new WeakMap();
function getKey(obj) {
function getKey(obj): string {
if (obj === null) return "null";
else if (obj === undefined) return "undefined";
@@ -22,7 +20,7 @@ function getKey(obj) {
return k;
}
export default function memoize(func) {
export default function memoize(func): Function {
return (...args) => {
const key = JSON.stringify(args.map(getKey)) + getKey(func);
@@ -14,9 +14,10 @@
* The code is very similar to the pure table solver, except we use a
* unit-propagating, derived-varlist-returing satisfiableAt.
*/
"use strict";
function satisfiableAt(clauses, varVals, varnr, val) {
/* eslint-disable @typescript-eslint/no-use-before-define */
function satisfiableAt(clauses, varVals, varnr, val): boolean {
if (varnr !== 0) varVals[varnr] = val;
const propRes = unitPropagate(clauses, varVals);
@@ -87,7 +88,7 @@ function satisfiableAt(clauses, varVals, varnr, val) {
* undetermined. The values of variables on the list will be restored (set to
* 0) during backtracking.
*/
function unitPropagate(clauses, varVals) {
function unitPropagate(clauses, varVals): number[] | 1 | -1 {
// all vars with a value derived in the forthcoming main loop
const derivedVars = [];
@@ -167,7 +168,7 @@ function unitPropagate(clauses, varVals) {
return derivedVars;
}
export function naiveDpll(clauses, maxvarnr) {
export function naiveDpll(clauses, maxvarnr): boolean {
// variable values are 0 if not set, 1 if positive, -1 if negative
const varVals = new Int32Array(maxvarnr + 1);
return satisfiableAt(clauses, varVals, 0, 0);
-3
View File
@@ -1,3 +0,0 @@
export default function pass() {
return 1;
}
+3
View File
@@ -0,0 +1,3 @@
export default function pass(): number {
return 1;
}
@@ -1,4 +1,4 @@
export default function test(resourceType, resource) {
export default function test(resourceType, resource): number {
if (resourceType === "devices") {
if (resource["Tags.test"] && resource["Tags.test"].value[0]) return 1;
} else if (resourceType === "presets") {