|
|
|
|
|
|
|
|
const postfixRE = /[?#].*$/; |
|
|
function cleanUrl(url) { |
|
|
return url.replace(postfixRE, ""); |
|
|
} |
|
|
function extractQueryWithoutFragment(url) { |
|
|
const questionMarkIndex = url.indexOf("?"); |
|
|
if (questionMarkIndex === -1) return ""; |
|
|
const fragmentIndex = url.indexOf("#", questionMarkIndex); |
|
|
if (fragmentIndex === -1) return url.substring(questionMarkIndex); |
|
|
else return url.substring(questionMarkIndex, fragmentIndex); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var And = class { |
|
|
kind; |
|
|
args; |
|
|
constructor(...args) { |
|
|
if (args.length === 0) throw new Error("`And` expects at least one operand"); |
|
|
this.args = args; |
|
|
this.kind = "and"; |
|
|
} |
|
|
}; |
|
|
var Or = class { |
|
|
kind; |
|
|
args; |
|
|
constructor(...args) { |
|
|
if (args.length === 0) throw new Error("`Or` expects at least one operand"); |
|
|
this.args = args; |
|
|
this.kind = "or"; |
|
|
} |
|
|
}; |
|
|
var Not = class { |
|
|
kind; |
|
|
expr; |
|
|
constructor(expr) { |
|
|
this.expr = expr; |
|
|
this.kind = "not"; |
|
|
} |
|
|
}; |
|
|
var Id = class { |
|
|
kind; |
|
|
pattern; |
|
|
params; |
|
|
constructor(pattern, params) { |
|
|
this.pattern = pattern; |
|
|
this.kind = "id"; |
|
|
this.params = params ?? { cleanUrl: false }; |
|
|
} |
|
|
}; |
|
|
var ModuleType = class { |
|
|
kind; |
|
|
pattern; |
|
|
constructor(pattern) { |
|
|
this.pattern = pattern; |
|
|
this.kind = "moduleType"; |
|
|
} |
|
|
}; |
|
|
var Code = class { |
|
|
kind; |
|
|
pattern; |
|
|
constructor(expr) { |
|
|
this.pattern = expr; |
|
|
this.kind = "code"; |
|
|
} |
|
|
}; |
|
|
var Query = class { |
|
|
kind; |
|
|
key; |
|
|
pattern; |
|
|
constructor(key, pattern) { |
|
|
this.pattern = pattern; |
|
|
this.key = key; |
|
|
this.kind = "query"; |
|
|
} |
|
|
}; |
|
|
var Include = class { |
|
|
kind; |
|
|
expr; |
|
|
constructor(expr) { |
|
|
this.expr = expr; |
|
|
this.kind = "include"; |
|
|
} |
|
|
}; |
|
|
var Exclude = class { |
|
|
kind; |
|
|
expr; |
|
|
constructor(expr) { |
|
|
this.expr = expr; |
|
|
this.kind = "exclude"; |
|
|
} |
|
|
}; |
|
|
function and(...args) { |
|
|
return new And(...args); |
|
|
} |
|
|
function or(...args) { |
|
|
return new Or(...args); |
|
|
} |
|
|
function not(expr) { |
|
|
return new Not(expr); |
|
|
} |
|
|
function id(pattern, params) { |
|
|
return new Id(pattern, params); |
|
|
} |
|
|
function moduleType(pattern) { |
|
|
return new ModuleType(pattern); |
|
|
} |
|
|
function code(pattern) { |
|
|
return new Code(pattern); |
|
|
} |
|
|
function query(key, pattern) { |
|
|
return new Query(key, pattern); |
|
|
} |
|
|
function include(expr) { |
|
|
return new Include(expr); |
|
|
} |
|
|
function exclude(expr) { |
|
|
return new Exclude(expr); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function queries(queryFilter) { |
|
|
let arr = Object.entries(queryFilter).map(([key, value]) => { |
|
|
return new Query(key, value); |
|
|
}); |
|
|
return and(...arr); |
|
|
} |
|
|
function interpreter(exprs, code$1, id$1, moduleType$1) { |
|
|
let arr = []; |
|
|
if (Array.isArray(exprs)) arr = exprs; |
|
|
else arr = [exprs]; |
|
|
return interpreterImpl(arr, code$1, id$1, moduleType$1); |
|
|
} |
|
|
function interpreterImpl(expr, code$1, id$1, moduleType$1, ctx = {}) { |
|
|
let hasInclude = false; |
|
|
for (const e of expr) switch (e.kind) { |
|
|
case "include": |
|
|
hasInclude = true; |
|
|
if (exprInterpreter(e.expr, code$1, id$1, moduleType$1, ctx)) return true; |
|
|
break; |
|
|
case "exclude": |
|
|
if (exprInterpreter(e.expr, code$1, id$1, moduleType$1)) return false; |
|
|
break; |
|
|
} |
|
|
return !hasInclude; |
|
|
} |
|
|
function exprInterpreter(expr, code$1, id$1, moduleType$1, ctx = {}) { |
|
|
switch (expr.kind) { |
|
|
case "and": return expr.args.every((e) => exprInterpreter(e, code$1, id$1, moduleType$1, ctx)); |
|
|
case "or": return expr.args.some((e) => exprInterpreter(e, code$1, id$1, moduleType$1, ctx)); |
|
|
case "not": return !exprInterpreter(expr.expr, code$1, id$1, moduleType$1, ctx); |
|
|
case "id": |
|
|
if (id$1 === void 0) throw new Error("`id` is required for `id` expression"); |
|
|
if (expr.params.cleanUrl) id$1 = cleanUrl(id$1); |
|
|
return typeof expr.pattern === "string" ? id$1 === expr.pattern : expr.pattern.test(id$1); |
|
|
case "moduleType": |
|
|
if (moduleType$1 === void 0) throw new Error("`moduleType` is required for `moduleType` expression"); |
|
|
return moduleType$1 === expr.pattern; |
|
|
case "code": |
|
|
if (code$1 === void 0) throw new Error("`code` is required for `code` expression"); |
|
|
return typeof expr.pattern === "string" ? code$1.includes(expr.pattern) : expr.pattern.test(code$1); |
|
|
case "query": { |
|
|
if (id$1 === void 0) throw new Error("`id` is required for `Query` expression"); |
|
|
if (!ctx.urlSearchParamsCache) { |
|
|
let queryString = extractQueryWithoutFragment(id$1); |
|
|
ctx.urlSearchParamsCache = new URLSearchParams(queryString); |
|
|
} |
|
|
let urlParams = ctx.urlSearchParamsCache; |
|
|
if (typeof expr.pattern === "boolean") if (expr.pattern) return urlParams.has(expr.key); |
|
|
else return !urlParams.has(expr.key); |
|
|
else if (typeof expr.pattern === "string") return urlParams.get(expr.key) === expr.pattern; |
|
|
else return expr.pattern.test(urlParams.get(expr.key) ?? ""); |
|
|
} |
|
|
default: throw new Error(`Expression ${JSON.stringify(expr)} is not expected.`); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function exactRegex(str, flags) { |
|
|
return new RegExp(`^${escapeRegex(str)}$`, flags); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function prefixRegex(str, flags) { |
|
|
return new RegExp(`^${escapeRegex(str)}`, flags); |
|
|
} |
|
|
const escapeRegexRE = /[-/\\^$*+?.()|[\]{}]/g; |
|
|
function escapeRegex(str) { |
|
|
return str.replace(escapeRegexRE, "\\$&"); |
|
|
} |
|
|
function makeIdFiltersToMatchWithQuery(input) { |
|
|
if (!Array.isArray(input)) return makeIdFilterToMatchWithQuery(input); |
|
|
return input.map((i) => makeIdFilterToMatchWithQuery(i)); |
|
|
} |
|
|
function makeIdFilterToMatchWithQuery(input) { |
|
|
if (typeof input === "string") return `${input}{?*,}`; |
|
|
return makeRegexIdFilterToMatchWithQuery(input); |
|
|
} |
|
|
function makeRegexIdFilterToMatchWithQuery(input) { |
|
|
return new RegExp(input.source.replace(/(?<!\\)\$/g, "(?:\\?.*)?$"), input.flags); |
|
|
} |
|
|
|
|
|
|
|
|
exports.and = and; |
|
|
exports.code = code; |
|
|
exports.exactRegex = exactRegex; |
|
|
exports.exclude = exclude; |
|
|
exports.exprInterpreter = exprInterpreter; |
|
|
exports.id = id; |
|
|
exports.include = include; |
|
|
exports.interpreter = interpreter; |
|
|
exports.interpreterImpl = interpreterImpl; |
|
|
exports.makeIdFiltersToMatchWithQuery = makeIdFiltersToMatchWithQuery; |
|
|
exports.moduleType = moduleType; |
|
|
exports.not = not; |
|
|
exports.or = or; |
|
|
exports.prefixRegex = prefixRegex; |
|
|
exports.queries = queries; |
|
|
exports.query = query; |