* configurable host overrides * base host overrides on name of service instead of key and hide the options by default * added unit tests * review changes * Refactor options * Refactor * Update Readme * Pump version and update Changelog Co-authored-by: Tobias Jacksteit <me@xtj7.de>
137 lines
3.5 KiB
JavaScript
137 lines
3.5 KiB
JavaScript
import UrlPattern from "url-pattern"
|
|
import { isFunction, isUndefined, compose, toPairs, map, pipe, isNil, reduce } from "lodash/fp"
|
|
import { asArray } from "./index"
|
|
import queryString from "query-string"
|
|
|
|
function parseUrl(url) {
|
|
const urlObject = new URL(url)
|
|
const { origin, pathname, search } = urlObject
|
|
let { hash } = urlObject
|
|
const query = {
|
|
...queryString.parse(search),
|
|
...queryString.parse(hash),
|
|
}
|
|
if (hash) {
|
|
hash = hash.match(/#[^&]+/)[0]
|
|
}
|
|
return { origin, pathname, hash, query }
|
|
}
|
|
|
|
function extractQueryParams(queryParams, query) {
|
|
return toPairs(queryParams).reduce((acc, [key, params]) => {
|
|
const param = asArray(params).find((param) => !isNil(query[param]))
|
|
if (param) {
|
|
acc[key] = query[param]
|
|
}
|
|
return acc
|
|
}, {})
|
|
}
|
|
|
|
const createEvaluator = (args) => (fnOrValue) => {
|
|
if (isUndefined(fnOrValue)) {
|
|
return
|
|
}
|
|
|
|
if (isFunction(fnOrValue)) {
|
|
return fnOrValue(...args)
|
|
}
|
|
|
|
return fnOrValue
|
|
}
|
|
|
|
const prepareHostForRegExp = (host) => {
|
|
return host.replace(":", "\\:")
|
|
}
|
|
|
|
const replaceHostInPattern = (host, pattern) => {
|
|
if (typeof pattern === "string") {
|
|
return pattern.replace(":host:", prepareHostForRegExp(host))
|
|
} else if (pattern instanceof RegExp) {
|
|
return new RegExp(pattern.source.replace(":host:", prepareHostForRegExp(host)))
|
|
} else {
|
|
return pattern
|
|
}
|
|
}
|
|
|
|
const parseServices = compose(
|
|
map(([key, config]) => ({
|
|
...config,
|
|
key,
|
|
patterns: config.urlPatterns.map((pattern) => {
|
|
if (Array.isArray(pattern)) {
|
|
return new UrlPattern(...pattern.map((p) => replaceHostInPattern(config.host, p)))
|
|
}
|
|
return new UrlPattern(replaceHostInPattern(config.host, pattern))
|
|
}),
|
|
})),
|
|
toPairs,
|
|
)
|
|
|
|
export const createEnhancer = (document) => (service) => {
|
|
if (!service) {
|
|
return
|
|
}
|
|
|
|
const match = service.match
|
|
const args = [document, service, match]
|
|
const evaluate = createEvaluator(args)
|
|
|
|
return {
|
|
...service,
|
|
id: evaluate(service.id),
|
|
description: evaluate(service.description),
|
|
projectId: evaluate(service.projectId),
|
|
taskId: evaluate(service.taskId),
|
|
position: service.position || { right: "calc(2rem + 5px)" },
|
|
}
|
|
}
|
|
|
|
const applyHostOverrides = (remoteServices, hostOverrides) =>
|
|
pipe(
|
|
toPairs,
|
|
reduce((acc, [key, remoteService]) => {
|
|
acc[key] = {
|
|
...remoteService,
|
|
key,
|
|
host: hostOverrides[remoteService.name] || remoteService.host,
|
|
}
|
|
return acc
|
|
}, {}),
|
|
)(remoteServices)
|
|
|
|
export const createMatcher = (remoteServices, hostOverrides) => {
|
|
const services = parseServices(applyHostOverrides(remoteServices, hostOverrides))
|
|
|
|
return (tabUrl) => {
|
|
const { origin, pathname, hash, query } = parseUrl(tabUrl)
|
|
const url = `${origin}${pathname}${hash}`
|
|
const service = services.find((service) => {
|
|
return service.patterns.some((pattern) => pattern.match(url))
|
|
})
|
|
|
|
if (!service) {
|
|
return
|
|
}
|
|
|
|
const pattern = service.patterns.find((pattern) => pattern.match(url))
|
|
let match = pattern.match(url)
|
|
if (service.queryParams) {
|
|
const extractedQueryParams = extractQueryParams(service.queryParams, query)
|
|
match = { ...extractedQueryParams, ...match }
|
|
}
|
|
|
|
return {
|
|
...match,
|
|
...service,
|
|
url: tabUrl,
|
|
match,
|
|
}
|
|
}
|
|
}
|
|
|
|
export const createServiceFinder = (remoteServices, hostOverrides) => (document) => {
|
|
const matcher = createMatcher(remoteServices, hostOverrides)
|
|
const enhancer = createEnhancer(document)
|
|
return pipe(matcher, enhancer)
|
|
}
|