{"version":3,"file":"profiles.cjs","names":[],"sources":["../src/profiles.ts"],"sourcesContent":["/**\n * Profile inheritance: a profile may `extends` other profiles and then state only what differs.\n *\n * Extending only adds. A profile's deny, ask and allow lists are its parents' lists followed by its own, so a child cannot remove\n * a restriction a parent set. The default mode is the profile's own, else the last parent's that sets one.\n */\n\nimport type { PermissionTiers, Profiles } from \"./schema.ts\";\n\n/** Where a profile's `extends` does not lead to a usable parent. */\nexport interface ProfileProblem {\n  /** The profile whose `extends` is wrong. */\n  profile: string;\n  message: string;\n}\n\n/** Every profile whose `extends` names a profile that does not exist, or that loops back on itself. */\nexport function profileProblems(\n  profiles: Profiles | undefined,\n): ProfileProblem[] {\n  const problems: ProfileProblem[] = [];\n  const all = profiles ?? {};\n  for (const [name, profile] of Object.entries(all)) {\n    for (const parent of profile.extends ?? []) {\n      if (!(parent in all)) {\n        problems.push({\n          profile: name,\n          message: `profile \"${name}\" extends \"${parent}\", which does not exist`,\n        });\n      }\n    }\n  }\n  if (problems.length > 0) return problems;\n\n  for (const name of Object.keys(all)) {\n    const cycle = findCycle(all, name, []);\n    if (cycle !== undefined) {\n      problems.push({\n        profile: name,\n        message: `profiles extend each other in a cycle: ${cycle.join(\" -> \")}`,\n      });\n      break;\n    }\n  }\n  return problems;\n}\n\n/** The chain that leads from `name` back to a profile already on the path, or `undefined`. */\nfunction findCycle(\n  profiles: Profiles,\n  name: string,\n  path: readonly string[],\n): string[] | undefined {\n  if (path.includes(name)) return [...path.slice(path.indexOf(name)), name];\n  for (const parent of profiles[name]?.extends ?? []) {\n    const cycle = findCycle(profiles, parent, [...path, name]);\n    if (cycle !== undefined) return cycle;\n  }\n  return undefined;\n}\n\n/**\n * Flatten `extends`: every profile with its parents' rules ahead of its own and no `extends` left.\n *\n * @throws Error if a profile extends one that does not exist or the profiles extend each other in a cycle.\n */\nexport function resolveProfiles(\n  profiles: Profiles | undefined,\n): Record<string, PermissionTiers> {\n  const all = profiles ?? {};\n  const problem = profileProblems(all)[0];\n  if (problem !== undefined) throw new Error(problem.message);\n\n  const resolved: Record<string, PermissionTiers> = {};\n  const resolve = (name: string): PermissionTiers => {\n    const cached = resolved[name];\n    if (cached !== undefined) return cached;\n    const { extends: parents = [], ...own } = all[name] ?? {};\n    const result: PermissionTiers = {};\n    for (const source of [...parents.map(resolve), own]) {\n      for (const list of [\n        \"deny\",\n        \"ask\",\n        \"allow\",\n        \"additionalDirectories\",\n      ] as const) {\n        const merged = [...(result[list] ?? []), ...(source[list] ?? [])];\n        if (merged.length > 0) result[list] = [...new Set(merged)];\n      }\n      if (source.defaultMode !== undefined)\n        result.defaultMode = source.defaultMode;\n    }\n    resolved[name] = result;\n    return result;\n  };\n  for (const name of Object.keys(all)) resolve(name);\n  return resolved;\n}\n"],"mappings":";;;AAiBA,SAAgB,gBACd,UACkB;CAClB,MAAM,WAA6B,CAAC;CACpC,MAAM,MAAM,YAAY,CAAC;CACzB,KAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,GAAG,GAC9C,KAAK,MAAM,UAAU,QAAQ,WAAW,CAAC,GACvC,IAAI,EAAE,UAAU,MACd,SAAS,KAAK;EACZ,SAAS;EACT,SAAS,YAAY,KAAK,aAAa,OAAO;CAChD,CAAC;CAIP,IAAI,SAAS,SAAS,GAAG,OAAO;CAEhC,KAAK,MAAM,QAAQ,OAAO,KAAK,GAAG,GAAG;EACnC,MAAM,QAAQ,UAAU,KAAK,MAAM,CAAC,CAAC;EACrC,IAAI,UAAU,QAAW;GACvB,SAAS,KAAK;IACZ,SAAS;IACT,SAAS,0CAA0C,MAAM,KAAK,MAAM;GACtE,CAAC;GACD;EACF;CACF;CACA,OAAO;AACT;;AAGA,SAAS,UACP,UACA,MACA,MACsB;CACtB,IAAI,KAAK,SAAS,IAAI,GAAG,OAAO,CAAC,GAAG,KAAK,MAAM,KAAK,QAAQ,IAAI,CAAC,GAAG,IAAI;CACxE,KAAK,MAAM,UAAU,SAAS,KAAK,EAAE,WAAW,CAAC,GAAG;EAClD,MAAM,QAAQ,UAAU,UAAU,QAAQ,CAAC,GAAG,MAAM,IAAI,CAAC;EACzD,IAAI,UAAU,QAAW,OAAO;CAClC;AAEF;;;;;;AAOA,SAAgB,gBACd,UACiC;CACjC,MAAM,MAAM,YAAY,CAAC;CACzB,MAAM,UAAU,gBAAgB,GAAG,CAAC,CAAC;CACrC,IAAI,YAAY,QAAW,MAAM,IAAI,MAAM,QAAQ,OAAO;CAE1D,MAAM,WAA4C,CAAC;CACnD,MAAM,WAAW,SAAkC;EACjD,MAAM,SAAS,SAAS;EACxB,IAAI,WAAW,QAAW,OAAO;EACjC,MAAM,EAAE,SAAS,UAAU,CAAC,GAAG,GAAG,QAAQ,IAAI,SAAS,CAAC;EACxD,MAAM,SAA0B,CAAC;EACjC,KAAK,MAAM,UAAU,CAAC,GAAG,QAAQ,IAAI,OAAO,GAAG,GAAG,GAAG;GACnD,KAAK,MAAM,QAAQ;IACjB;IACA;IACA;IACA;GACF,GAAY;IACV,MAAM,SAAS,CAAC,GAAI,OAAO,SAAS,CAAC,GAAI,GAAI,OAAO,SAAS,CAAC,CAAE;IAChE,IAAI,OAAO,SAAS,GAAG,OAAO,QAAQ,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC;GAC3D;GACA,IAAI,OAAO,gBAAgB,QACzB,OAAO,cAAc,OAAO;EAChC;EACA,SAAS,QAAQ;EACjB,OAAO;CACT;CACA,KAAK,MAAM,QAAQ,OAAO,KAAK,GAAG,GAAG,QAAQ,IAAI;CACjD,OAAO;AACT"}