import {type JsonValue, fromCanonicalJson, CanonicalPrimitive} from "./content-canonical"; export function buildContent( locale: string | undefined, locales: string[], variant: string | undefined, variants: string[], content: JsonValue ): [JsonValue, boolean] { function check(all: string[], specified: string[], query: string): boolean { const related = specified.filter(t => all.includes(t)) all = related.length ? related : all return all.includes(query) } function predicate(tags?: string[]) { if (!tags || !tags.length) { return true } if (locale && !check(locales, tags, locale)) { return false } return !variant || check(variants, tags, variant) } const options = {predicate: predicate, expand: false} const canonical = fromCanonicalJson(content) const reduced = canonical.reduce(options) return [reduced, options.expand] } export function expandContent(content: JsonValue, sources: JsonValue[]): JsonValue { function resolve(key: string): JsonValue { for (const source of sources) { const value = getPath(source, key) if (value !== undefined) { return value } } return `$\{${key}\}` } function traverse(item: JsonValue): JsonValue { if (item !== null) { if (item instanceof CanonicalPrimitive) { return item.resolve(resolve) } else if (Array.isArray(item)) { return item.map(i => traverse(i)) } else if (typeof item === 'object') { const record: Record = {} for (const [k, v] of Object.entries(item)) { record[k] = traverse(v) } return record } } return item } return traverse(content) } // function getPath(obj: any, path: string, sep = '.'): any { // TODO REFACTOR THIS // const keys = path.split(sep) // let cur = obj // // for (const key of keys) { // if (cur == null || typeof cur !== 'object') return undefined // cur = cur[key] // } // // return cur // } function toPath(path: string): Array { // Matches: // - bare tokens: foo, bar // - [123] numeric indices // - ["str"] or ['str'] quoted keys const re = /[^.[\]]+|\[(?:([0-9]+)|(["'])(.*?)\2)\]/g; const tokens: Array = []; let m: RegExpExecArray | null; while ((m = re.exec(path))) { if (m[1] !== undefined) { tokens.push(Number(m[1])); // [123] } else if (m[3] !== undefined) { tokens.push(m[3]); // ["key"] / ['key'] } else { tokens.push(m[0]); // bare token } } return tokens; } function getPath(obj: unknown, path: string): JsonValue | undefined { const steps = toPath(path); let cur: any = obj; for (const step of steps) { if (cur == null) return undefined; if (typeof step === 'number') { if (!Array.isArray(cur) || step < 0 || step >= cur.length) return undefined; cur = cur[step]; } else { cur = cur[step]; } } return cur as JsonValue; }