var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
var __typeError = (msg) => {
  throw TypeError(msg);
};
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __decoratorStart = (base) => [, , , __create(base?.[__knownSymbol("metadata")] ?? null)];
var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn;
var __decoratorContext = (kind, name, done, metadata, fns) => ({ kind: __decoratorStrings[kind], name, metadata, addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null)) });
var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
var __runInitializers = (array, flags, self, value) => {
  for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) flags & 1 ? fns[i].call(self) : value = fns[i].call(self, value);
  return value;
};
var __decorateElement = (array, flags, name, decorators, target, extra) => {
  var fn, it, done, ctx, access, k = flags & 7, s = !!(flags & 8), p = !!(flags & 16);
  var j = k > 3 ? array.length + 1 : k ? s ? 1 : 2 : 0, key = __decoratorStrings[k + 5];
  var initializers = k > 3 && (array[j - 1] = []), extraInitializers = array[j] || (array[j] = []);
  var desc = k && (!p && !s && (target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(k < 4 ? target : { get [name]() {
    return __privateGet(this, extra);
  }, set [name](x) {
    return __privateSet(this, extra, x);
  } }, name));
  k ? p && k < 4 && __name(extra, (k > 2 ? "set " : k > 1 ? "get " : "") + name) : __name(target, name);
  for (var i = decorators.length - 1; i >= 0; i--) {
    ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
    if (k) {
      ctx.static = s, ctx.private = p, access = ctx.access = { has: p ? (x) => __privateIn(target, x) : (x) => name in x };
      if (k ^ 3) access.get = p ? (x) => (k ^ 1 ? __privateGet : __privateMethod)(x, target, k ^ 4 ? extra : desc.get) : (x) => x[name];
      if (k > 2) access.set = p ? (x, y) => __privateSet(x, target, y, k ^ 4 ? extra : desc.set) : (x, y) => x[name] = y;
    }
    it = (0, decorators[i])(k ? k < 4 ? p ? extra : desc[key] : k > 4 ? void 0 : { get: desc.get, set: desc.set } : target, ctx), done._ = 1;
    if (k ^ 4 || it === void 0) __expectFn(it) && (k > 4 ? initializers.unshift(it) : k ? p ? extra = it : desc[key] = it : target = it);
    else if (typeof it !== "object" || it === null) __typeError("Object expected");
    else __expectFn(fn = it.get) && (desc.get = fn), __expectFn(fn = it.set) && (desc.set = fn), __expectFn(fn = it.init) && initializers.unshift(fn);
  }
  return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
};
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use the "in" operator on this value') : member.has(obj);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);

// src/core/meta/hooks.ts
import { AsyncSeriesWaterfallHook } from "tapable";
import { generateHooksAccess } from "@diplodoc/cli/lib/utils";
function hooks(name) {
  return {
    Dump: new AsyncSeriesWaterfallHook(
      ["meta", "path"],
      `${name}.Dump`
    )
  };
}
var [getHooks, withHooks] = generateHooksAccess("Meta", hooks);

// src/core/meta/MetaService.ts
import { flow, omit, uniq } from "lodash";
import { copyJson, get, normalizePath, shortLink, zip } from "@diplodoc/cli/lib/utils";
var _MetaService_decorators, _init;
_MetaService_decorators = [withHooks];
var MetaService = class {
  /**
   * Creates a new MetaService instance.
   *
   * @param run - Run instance with configuration
   */
  constructor(run) {
    this.name = "Meta";
    // private run: Run<Config>;
    this.config = void 0;
    this.meta = /* @__PURE__ */ new Map();
    this.config = run.config;
  }
  /**
   * Returns current metadata for a path (creates initial metadata if not exists).
   *
   * Returns a frozen, read-only copy to prevent accidental modifications.
   * This is the non-normalized version - use `dump()` for final normalized metadata.
   *
   * @param path - Relative path to the document
   * @returns Frozen copy of metadata for the path
   */
  get(path) {
    const file = normalizePath(path);
    if (!this.meta.has(file)) {
      this.meta.set(file, this.initialMeta());
    }
    return this.meta.get(file);
  }
  /**
   * Sets metadata for a path (overwrites existing).
   *
   * @param path - Relative path to the document
   * @param meta - Metadata object to set
   */
  set(path, meta) {
    const file = normalizePath(path);
    this.meta.set(file, meta);
  }
  /**
   * Returns normalized, merged metadata for a path.
   *
   * Performs cleanup operations:
   * - Removes duplicates from arrays (script, style, keywords)
   * - Removes empty arrays (script, style, keywords, contributors, csp, alternate)
   * - Removes empty objects (metadata, __system)
   * - Runs Dump hook for final processing
   *
   * @param path - Relative path to the document
   * @returns Normalized metadata ready for use
   */
  async dump(path) {
    const file = normalizePath(path);
    const meta = copyJson(this.meta.get(file)) || this.initialMeta();
    for (const field of ["script", "style", "keywords"]) {
      if (!meta[field]) {
        continue;
      }
      meta[field] = uniq(meta[field]).filter(Boolean);
    }
    if (meta.alternate?.length) {
      meta.alternate.sort((a, b) => a.href > b.href ? 1 : -1);
    }
    for (const field of [
      "script",
      "style",
      "keywords",
      "contributors",
      "csp",
      "alternate"
    ]) {
      if (!meta[field]?.length) {
        delete meta[field];
      }
    }
    for (const field of ["metadata", "__system"]) {
      if (!meta[field]) {
        continue;
      }
      if (!Object.keys(meta[field]).length) {
        delete meta[field];
      }
    }
    return getHooks(this).Dump.promise(meta, file);
  }
  /**
   * Adds/merges metadata for a path.
   *
   * Handles special fields:
   * - `restricted-access`: Prevents duplicate access rules
   * - `metadata`: Custom meta tags (merged via `addMetadata()`)
   * - `alternate`: Alternate links (merged via `addAlternates()`)
   * - `__system`: System variables (merged via `addSystemVars()`)
   * - Other fields: Direct assignment (last value wins)
   *
   * @param path - Relative path to the document
   * @param record - Hash of metadata fields to add/merge
   * @param isRaw - Is metadata from load
   * @returns Updated metadata object
   */
  add(path, record, isRaw = false) {
    const file = normalizePath(path);
    if (this.config.rawAddMeta) {
      if (isRaw) {
        this.meta.set(file, record);
      }
      return;
    }
    const meta = this.meta.get(file) || this.initialMeta();
    if (meta["restricted-access"]?.length && record["restricted-access"]) {
      for (const access of meta["restricted-access"]) {
        record["restricted-access"] = record["restricted-access"].filter(
          (recordAccess) => recordAccess.sort().join(",") !== access.slice().sort().join(",")
        );
      }
    }
    if (record["restricted-access"]?.length > 0) {
      meta["restricted-access"] = [
        ...meta["restricted-access"] || [],
        ...record["restricted-access"]
      ];
    }
    const result = Object.assign(
      meta,
      omit(record, [
        "script",
        "style",
        "csp",
        "metadata",
        "alternate",
        "__system",
        "restricted-access"
      ])
    );
    this.meta.set(file, result);
    this.addMetadata(path, record.metadata);
    this.addAlternates(path, record.alternate);
    this.addSystemVars(path, record.__system);
    return meta;
  }
  /**
   * Adds page resources (scripts, styles, CSP) for a path.
   *
   * Scripts and styles are merged as unique arrays.
   * CSP records are normalized (strings converted to arrays).
   *
   * @param path - Relative path to the document
   * @param resources - Raw resources to add (undefined is ignored)
   */
  addResources(path, resources) {
    const file = normalizePath(path);
    if (!resources || !this.config.addResourcesMeta) {
      return;
    }
    const meta = this.meta.get(file) || this.initialMeta();
    if (Array.isArray(resources.script)) {
      meta.script = uniq([...meta.script || [], ...resources.script]);
    }
    if (Array.isArray(resources.style)) {
      meta.style = uniq([...meta.style || [], ...resources.style]);
    }
    if (Array.isArray(resources.csp)) {
      const records = [];
      for (const csp of resources.csp) {
        const record = {};
        for (const [key, value] of Object.entries(csp)) {
          record[key] = [].concat(value);
        }
        records.push(record);
      }
      meta.csp = [...meta.csp || [], ...records];
    }
    this.meta.set(file, meta);
  }
  /**
   * Adds custom meta tags for a path.
   *
   * Accepts hash or array of meta items.
   * Prevents duplicates by name/content or property/content.
   *
   * @param path - Relative path to the document
   * @param metadata - Hash of meta tags or array of meta items (undefined is ignored)
   */
  addMetadata(path, metadata) {
    const file = normalizePath(path);
    if (!metadata || !this.config.addMetadataMeta) {
      return;
    }
    if (!Array.isArray(metadata)) {
      metadata = Object.entries(metadata).map(([name, content]) => ({ name, content }));
    }
    const meta = this.meta.get(file) || this.initialMeta();
    meta.metadata = meta.metadata || [];
    metadata.forEach((item) => {
      if (!meta.metadata?.find(
        (metaItem) => metaItem.name === item.name && metaItem.content === item.content || metaItem.property === item.property && metaItem.content === item.content
      )) {
        meta.metadata?.push(item);
      }
    });
    this.meta.set(file, meta);
  }
  /**
   * Adds alternate language links for a path.
   *
   * Accepts paths (strings) or Alternate objects.
   * Prevents duplicates by normalized href using short link comparison.
   *
   * @param path - Relative path to the document
   * @param alternates - Array of alternate paths or Alternate objects (undefined is ignored)
   */
  addAlternates(path, alternates) {
    const file = normalizePath(path);
    const normalized = (alternates || []).map((item) => {
      if (typeof item === "string") {
        return { href: item };
      }
      return item;
    });
    const hash = flow(get("href"), shortLink);
    const meta = this.meta.get(file) || this.initialMeta();
    const alternate = meta.alternate = meta.alternate || [];
    const curr = zip(alternate.map(hash), alternate);
    const next = zip(normalized.map(hash), normalized);
    for (const [key, value] of Object.entries(next)) {
      if (!curr[key]) {
        alternate.push(value);
      }
    }
    meta.alternate = alternate;
    this.meta.set(file, meta);
  }
  /**
   * Adds system variables for a path (only if config.addSystemMeta is enabled).
   *
   * Used for internal system metadata. Merged into `__system` field.
   *
   * @param path - Relative path to the document
   * @param vars - Hash of system variables to add (undefined is ignored)
   */
  addSystemVars(path, vars) {
    const file = normalizePath(path);
    if (!vars || !this.config.addSystemMeta) {
      return;
    }
    const meta = this.meta.get(file) || this.initialMeta();
    meta.__system = Object.assign({}, meta.__system, vars);
    this.meta.set(file, meta);
  }
  initialMeta() {
    return {
      metadata: [],
      alternate: [],
      style: [],
      script: [],
      csp: []
    };
  }
};
_init = __decoratorStart(null);
MetaService = __decorateElement(_init, 0, "MetaService", _MetaService_decorators, MetaService);
__runInitializers(_init, 1, MetaService);
export {
  MetaService,
  getHooks
};
//# sourceMappingURL=index.mjs.map
