Dominik Milacher cbfab733b7
All checks were successful
Build and deploy updated apps / Build & deploy (push) Successful in 1m46s
Fix content path bug
2025-10-14 21:52:01 +02:00

179 lines
4.8 KiB
TypeScript

import { isTemplate, expandTemplate } from '../utils/content-template'
import { computed } from 'vue'
import { useRoute } from '#app'
const specializations: Record<string, object> = {}
function buildSpecialization(locale: string, variant: string): object {
const config = useAppConfig()
const locales = config.content.matrix.locale.list.map(l => l.code)
const variants = config.content.matrix.variant.list.map(v => v.code)
const allTags = new Set([...locales, ...variants])
function split(key: string): {base?: string; tags: string[]} {
const parts = key.split('@')
if (allTags.has(parts[0])) {
return {base: undefined, tags: parts}
}
return {base: parts[0], tags: parts.slice(1)}
}
function relevant(tags: string[]): boolean {
if (tags.length < 1) {
return true
}
for (const tag of tags) {
if (tag !== locale && tag !== variant) {
return false
}
}
return true
}
function filterObject(object: any): any {
if (Array.isArray(object)) {
return object.map(e => filterObject(e)).filter(e => e !== undefined)
}
if (typeof object !== 'object') {
return object
}
const copy: Record<string, any> = {}
let anonymous: [number, any][] = []
for (const key in object) {
const {base, tags} = split(key)
if (!relevant(tags)) {
continue
}
const value = filterObject(object[key])
if (base === undefined) {
anonymous.push([tags.length, value])
} else {
copy[base] = value
}
}
if (Object.keys(copy).length > 0 && anonymous.length > 0) {
console.warn(`Invalid mixing of keys in object ${object}`)
}
if (Object.keys(copy).length > 0) {
return copy
}
if (anonymous.length < 1) {
console.warn("Unable to parse object", object)
}
anonymous.sort((a, b) => b[0] - a[0])
if (anonymous[0][0] > 2) {
console.warn(`More than two tags per key in object ${object}`)
}
return anonymous[0][1]
}
const filtered = filterObject(config.content)
function deepReplace(obj: any, predicate: (node: any) => boolean, replacer: (node: any) => any): void {
if (Array.isArray(obj)) {
for (let i = 0; i < obj.length; i++) {
if (predicate(obj[i])) {
obj[i] = replacer(obj[i]);
} else if (typeof obj[i] === 'object' && obj[i] !== null) {
deepReplace(obj[i], predicate, replacer);
}
}
} else if (typeof obj === 'object' && obj !== null) {
for (const key of Object.keys(obj)) {
if (predicate(obj[key])) {
obj[key] = replacer(obj[key]);
} else if (typeof obj[key] === 'object' && obj[key] !== null) {
deepReplace(obj[key], predicate, replacer);
}
}
}
}
deepReplace(filtered, (node: any) => isTemplate(node), (node: any) => expandTemplate(node, filtered))
return filtered
}
function getSpecialization(locale: string, variant: string): object {
const key = locale + '/' + variant
if (!(key in specializations)) {
specializations[key] = buildSpecialization(locale, variant)
}
return specializations[key]
}
export function useContent() {
const config = useAppConfig()
const route = useRoute()
const {getLocaleVariant, buildPrefix} = useContentPrefix()
const locales = config.content.matrix.locale.list.map(l => l.code)
const variants = config.content.matrix.variant.list.map(v => v.code)
const localeVariant = computed(() => getLocaleVariant(route.path)!)
const currentLocale = computed(() => localeVariant.value[0])
const currentVariant = computed(() => localeVariant.value[1])
function matrixPath(options: { page?: string; anchor?: string; locale?: string; variant?: string }): string {
let page = options.page
if (page && !page.startsWith('/')) {
page = '/' + page
}
if (page === undefined) {
page = route.fullPath
const [locale, variant] = getLocaleVariant(page)!
const length = buildPrefix(locale, variant).length
page = page.slice(length)
}
const prefix = buildPrefix(options.locale ?? currentLocale.value, options.variant ?? currentVariant.value)
let base = prefix + page
if (base.endsWith('/')) {
base = base.slice(0, -1)
}
return options.anchor ? `${base}#${options.anchor}` : base
}
function p(page: string, anchor?: string): string {
return matrixPath({page: page, anchor: anchor})
}
const specialization = computed<any>(() => getSpecialization(currentLocale.value, currentVariant.value))
return {
locale: currentLocale,
locales: config.content.matrix.locale.list,
localeCodes: locales,
variant: currentVariant,
variants: config.content.matrix.variant.list,
variantCodes: variants,
matrixPath: matrixPath,
p: p,
c: specialization,
}
}