import { NumberWithUnitSymbol, DictionarySymbol, isObject, isNumber, isString, parseExpression, StringSymbol, NumberSymbol, isBoolean, BooleanSymbol, isNull, NullSymbol, isArray, isTokenscriptSymbol, symbolTypeToJsValue, getKeyAlt, Interpreter, TokenSymbol, jsValueToSymbolType } from '../chunk-YBOIEXQ6.js';
import { UNINTERPRETED_KEYWORDS } from '../chunk-MHMD6TZS.js';
import { type } from 'arktype';

// src/processor/builders/flatten.ts
function flattenChildrenObject(result, prefix, callback) {
  if (result instanceof DictionarySymbol) {
    flattenChildrenMap(result.value, prefix, callback);
  }
}
function flattenChildrenMap(map, prefix, callback) {
  for (const [key, value] of map.entries()) {
    const newKey = `${prefix}.${key}`;
    if (typeof value === "undefined") {
      continue;
    }
    if (value instanceof DictionarySymbol) {
      flattenChildrenMap(value.value, newKey, callback);
    } else {
      callback(newKey, value);
    }
  }
}

// src/processor/errors.ts
var DependencyError = class _DependencyError extends Error {
  constructor(tokenName, dependencyName, originalError) {
    const rootError = _DependencyError.extractRootError(originalError);
    const chain = [tokenName, ..._DependencyError.extractChain(originalError, dependencyName)];
    const chainStr = chain.join(" \u2192 ");
    super(
      `Token '${tokenName}' failed due to dependency error: ${chainStr}
Root cause: ${rootError.message}`
    );
    this.name = "DependencyError";
    this.dependencyChain = chain;
    this.rootError = rootError;
  }
  static extractChain(error, dependencyName) {
    if (error instanceof _DependencyError) {
      return [...error.dependencyChain];
    }
    return [dependencyName];
  }
  static extractRootError(error) {
    if (error instanceof _DependencyError) {
      return error.rootError;
    }
    return error;
  }
};

// src/processor/object-parsers/parsers/number-with-unit.ts
var numberWithUnitParser = {
  predicate: (value) => {
    if (!isObject(value)) {
      return false;
    }
    const obj = value;
    return "value" in obj && "unit" in obj && isNumber(obj.value) && isString(obj.unit) && Object.keys(obj).length === 2;
  },
  toSymbol: (value, config) => new NumberWithUnitSymbol(value.value, value.unit, config)
};

// src/processor/object-parsers/default-object-parsers.ts
var defaultObjectParsers = [numberWithUnitParser];

// src/processor/object-parsers/symbol-conversion.ts
function parseValueToSymbol(value, config, parsers = defaultObjectParsers) {
  if (value && typeof value === "object" && "getTypeName" in value) {
    return value;
  }
  for (const parser of parsers) {
    if (parser.predicate(value)) {
      return parser.toSymbol(value, config);
    }
  }
  return jsValueToSymbolType(value, config);
}
function createTokenSymbol(value, tokenType = "unknown", config, parsers = defaultObjectParsers) {
  if (isObject(value)) {
    const symbolMap = {};
    for (const [key, val] of Object.entries(value)) {
      symbolMap[key] = parseValueToSymbol(val, config, parsers);
    }
    return new TokenSymbol(tokenType, symbolMap, config);
  }
  if (isArray(value)) {
    const symbolArray = value.map((val) => parseValueToSymbol(val, config, parsers));
    return new TokenSymbol(tokenType, symbolArray, config);
  }
  return new TokenSymbol(tokenType, value, config);
}

// src/processor/utils/DependencyGraph.ts
var DependencyGraph = class {
  constructor() {
    this.nodes = /* @__PURE__ */ new Map();
  }
  addNode(node, dependencies = []) {
    if (!this.nodes.has(node)) {
      this.nodes.set(node, new Set(dependencies));
    }
  }
  getNodes() {
    return this.nodes;
  }
  // Find nodes with no dependencies
  entryNodes() {
    const entries = [];
    for (const [node, deps] of this.nodes) {
      if (deps.size === 0) {
        entries.push(node);
      }
    }
    return entries;
  }
  // Find a cycle in the graph starting from the given nodes
  findCycle(candidateNodes) {
    const visited = /* @__PURE__ */ new Set();
    const recursionStack = /* @__PURE__ */ new Set();
    const path = [];
    const dfs = (node) => {
      visited.add(node);
      recursionStack.add(node);
      path.push(node);
      const deps = this.nodes.get(node);
      if (deps) {
        for (const dep of deps) {
          if (!visited.has(dep)) {
            if (dfs(dep)) {
              return true;
            }
          } else if (recursionStack.has(dep)) {
            return true;
          }
        }
      }
      path.pop();
      recursionStack.delete(node);
      return false;
    };
    for (const node of candidateNodes) {
      if (!visited.has(node)) {
        if (dfs(node)) {
          return path;
        }
      }
    }
    return candidateNodes;
  }
  // Topological sort using Kahn's algorithm
  topologicalSort() {
    const inDegree = /* @__PURE__ */ new Map();
    const result = [];
    for (const node of this.nodes.keys()) {
      inDegree.set(node, 0);
    }
    for (const deps of this.nodes.values()) {
      for (const dep of deps) {
        inDegree.set(dep, (inDegree.get(dep) || 0) + 1);
      }
    }
    const queue = [];
    for (const [node, degree] of inDegree) {
      if (degree === 0) {
        queue.push(node);
      }
    }
    while (queue.length > 0) {
      const node = queue.shift();
      if (node === void 0) break;
      result.push(node);
      const deps = this.nodes.get(node) || /* @__PURE__ */ new Set();
      for (const dep of deps) {
        const newDegree = (inDegree.get(dep) || 0) - 1;
        inDegree.set(dep, newDegree);
        if (newDegree === 0) {
          queue.push(dep);
        }
      }
    }
    if (result.length !== this.nodes.size) {
      const resultSet = new Set(result);
      const remainingNodes = [];
      for (const node of this.nodes.keys()) {
        if (!resultSet.has(node)) {
          remainingNodes.push(node);
        }
      }
      const cycle = this.findCycle(remainingNodes);
      throw new Error(
        `Circular dependency detected: ${cycle.map((n) => String(n)).join(" \u2192 ")} \u2192 ${String(cycle[0])}`
      );
    }
    return result;
  }
};

// src/processor/utils/structured-tokens.ts
function extractStringFields(value, parentPath) {
  const result = /* @__PURE__ */ new Map();
  if (isObject(value)) {
    for (const [key, val] of Object.entries(value)) {
      const path = `${parentPath}.${key}`;
      if (isString(val)) {
        result.set(path, val);
      }
    }
  } else if (isArray(value)) {
    for (let i = 0; i < value.length; i++) {
      const item = value[i];
      const path = `${parentPath}[${i}]`;
      if (isString(item)) {
        result.set(path, item);
      }
    }
  }
  return result;
}
function assembleStructuredToken(tokenName, resolvedFields, originalValue) {
  if (isObject(originalValue)) {
    const result = {};
    for (const [key, val] of Object.entries(originalValue)) {
      const path = `${tokenName}.${key}`;
      if (resolvedFields.has(path)) {
        result[key] = resolvedFields.get(path);
      } else {
        result[key] = val;
      }
    }
    return result;
  }
  if (isArray(originalValue)) {
    const result = [];
    for (let i = 0; i < originalValue.length; i++) {
      const path = `${tokenName}[${i}]`;
      if (resolvedFields.has(path)) {
        result.push(resolvedFields.get(path));
      } else {
        result.push(originalValue[i]);
      }
    }
    return result;
  }
  return originalValue;
}

// src/processor/utils/tokens.ts
function getTokenValue(data) {
  return isString(data) ? data : data.$value;
}
function setTokenValue(value) {
  return isString(value) ? { $value: value } : value;
}
function flattenTokensObject(obj, prefixAccumulator = "") {
  const result = /* @__PURE__ */ new Map();
  for (const [prefix, value] of Object.entries(obj)) {
    if (prefix.startsWith("$")) {
      continue;
    }
    const path = prefixAccumulator ? `${prefixAccumulator}.${prefix}` : prefix;
    if (isObject(value)) {
      const objValue = value;
      const tokenValue = getKeyAlt(["$value", "value"], objValue);
      if (tokenValue !== void 0) {
        const tokenType = objValue.$type;
        const tokenData = {
          $value: tokenValue,
          ...tokenType !== void 0 && { $type: String(tokenType) }
        };
        result.set(path, tokenData);
      } else {
        const nested = flattenTokensObject(objValue, path);
        for (const [nestedKey, nestedValue] of nested) {
          result.set(nestedKey, nestedValue);
        }
      }
    } else {
      result.set(path, { $value: value });
    }
  }
  return result;
}
function recordToMap(record) {
  const map = /* @__PURE__ */ new Map();
  for (const [key, value] of Object.entries(record)) {
    map.set(key, { $value: value });
  }
  return map;
}
function isNested(obj) {
  return Object.keys(obj).some((key) => {
    const value = obj[key];
    return typeof value === "object" && value !== null && !Array.isArray(value) && !key.startsWith("$");
  });
}

// src/processor/resolver/DependencyTracker.ts
var DependencyTracker = class {
  constructor() {
    this.tokenDeps = /* @__PURE__ */ new Map();
    this.reverseDeps = /* @__PURE__ */ new Map();
    this.prefixDeps = /* @__PURE__ */ new Map();
    this.prefixReverseDeps = /* @__PURE__ */ new Map();
  }
  addTokenDependency(dependent, dependency) {
    this.addToSetMap(this.tokenDeps, dependent, dependency);
    this.addToSetMap(this.reverseDeps, dependency, dependent);
  }
  removeTokenDependency(dependent, dependency) {
    this.removeFromSetMap(this.tokenDeps, dependent, dependency);
    this.removeFromSetMap(this.reverseDeps, dependency, dependent);
  }
  addPrefixDependency(dependent, prefix) {
    this.addToSetMap(this.prefixDeps, dependent, prefix);
    this.addToSetMap(this.prefixReverseDeps, prefix, dependent);
  }
  removePrefixDependency(dependent, prefix) {
    this.removeFromSetMap(this.prefixDeps, dependent, prefix);
    this.removeFromSetMap(this.prefixReverseDeps, prefix, dependent);
  }
  getTokenDependents(token) {
    return this.cloneSet(this.reverseDeps.get(token));
  }
  getTokenDependentsIterable(token) {
    return this.reverseDeps.get(token) ?? [];
  }
  getTokensWaitingForPrefix(prefix) {
    return this.cloneSet(this.prefixReverseDeps.get(prefix));
  }
  getTokensWaitingForPrefixIterable(prefix) {
    return this.prefixReverseDeps.get(prefix) ?? [];
  }
  getTokenDependencies(token) {
    return this.cloneSet(this.tokenDeps.get(token));
  }
  getPrefixDependencies(token) {
    return this.cloneSet(this.prefixDeps.get(token));
  }
  isTokenReady(token) {
    const tokenDeps = this.tokenDeps.get(token);
    const prefixDeps = this.prefixDeps.get(token);
    return (!tokenDeps || tokenDeps.size === 0) && (!prefixDeps || prefixDeps.size === 0);
  }
  hasAnyDependencies() {
    return this.tokenDeps.size > 0 || this.prefixDeps.size > 0;
  }
  getUnresolvedTokens() {
    const unresolved = /* @__PURE__ */ new Set();
    for (const [token] of this.tokenDeps) unresolved.add(token);
    for (const [token] of this.prefixDeps) unresolved.add(token);
    return Array.from(unresolved);
  }
  addToSetMap(map, key, value) {
    let set = map.get(key);
    if (!set) {
      set = /* @__PURE__ */ new Set();
      map.set(key, set);
    }
    set.add(value);
  }
  removeFromSetMap(map, key, value) {
    const set = map.get(key);
    if (!set) return;
    set.delete(value);
    if (set.size === 0) {
      map.delete(key);
    }
  }
  cloneSet(values) {
    return values ? new Set(values) : /* @__PURE__ */ new Set();
  }
};

// src/processor/resolver/PrefixExtractor.ts
var PrefixExtractor = class {
  constructor() {
    this.prefixCache = /* @__PURE__ */ new Map();
  }
  /**
   * Extract all prefix paths for a token reference.
   *
   * Example: "a.b.c" returns ["a", "a.b"]
   * Cached after first call for the same token.
   */
  extractPrefixes(tokenName) {
    const cached = this.prefixCache.get(tokenName);
    if (cached) {
      return cached;
    }
    const prefixes = [];
    let dotIndex = tokenName.indexOf(".");
    while (dotIndex !== -1) {
      prefixes.push(tokenName.slice(0, dotIndex));
      dotIndex = tokenName.indexOf(".", dotIndex + 1);
    }
    this.prefixCache.set(tokenName, prefixes);
    return prefixes;
  }
  clearCache() {
    this.prefixCache.clear();
  }
};

// src/processor/resolver/PrefixManager.ts
var PrefixManager = class {
  constructor(config) {
    this.config = config;
    this.prefixes = /* @__PURE__ */ new Map();
    this.tokenPrefixes = /* @__PURE__ */ new Map();
    this.activePrefixes = /* @__PURE__ */ new Map();
    this.virtualChildren = /* @__PURE__ */ new Map();
    this.prefixExtractor = new PrefixExtractor();
    // Optimization caches
    this.directChildrenCache = /* @__PURE__ */ new Map();
    this.parentLookupCache = /* @__PURE__ */ new Map();
  }
  addTokenToPrefix(tokenName) {
    const prefixes = this.prefixExtractor.extractPrefixes(tokenName);
    if (prefixes.length === 0) return;
    for (const prefix of prefixes) {
      this.addToSetMap(this.prefixes, prefix, tokenName);
      this.addToSetMap(this.tokenPrefixes, tokenName, prefix);
      const prefixLen = prefix.length + 1;
      const shortName = tokenName.slice(prefixLen);
      if (!shortName.includes(".")) {
        this.addToSetMap(this.directChildrenCache, prefix, shortName);
      }
    }
  }
  hasPrefix(prefix) {
    return this.prefixes.has(prefix);
  }
  activatePrefix(prefix) {
    if (this.activePrefixes.has(prefix)) return;
    const members = this.prefixes.get(prefix);
    if (!members || members.size === 0) return;
    this.activePrefixes.set(prefix, new Set(members));
  }
  markTokenResolved(tokenName) {
    const prefixes = this.tokenPrefixes.get(tokenName);
    if (!prefixes || prefixes.size === 0) return [];
    const ready = [];
    for (const prefix of prefixes) {
      const pending = this.activePrefixes.get(prefix);
      if (!pending) continue;
      pending.delete(tokenName);
      if (pending.size === 0) {
        this.activePrefixes.delete(prefix);
        ready.push(prefix);
      }
    }
    this.tokenPrefixes.delete(tokenName);
    return ready;
  }
  buildPrefixDictionary(prefix, referenceCache) {
    const directChildren = this.directChildrenCache.get(prefix);
    if (!directChildren || directChildren.size === 0) return void 0;
    const dictionaryEntries = /* @__PURE__ */ new Map();
    for (const shortName of directChildren) {
      const tokenName = `${prefix}.${shortName}`;
      const referenceValue = referenceCache.get(tokenName);
      const symbol = this.toSymbol(referenceValue);
      if (symbol) {
        dictionaryEntries.set(shortName, symbol.cloneIfMutable());
      }
    }
    if (dictionaryEntries.size === 0) return void 0;
    return new DictionarySymbol(dictionaryEntries, this.config);
  }
  findParentToken(reference, tokens) {
    const cached = this.parentLookupCache.get(reference);
    if (cached !== void 0) {
      return cached === null ? void 0 : cached;
    }
    let lastDotIndex = reference.lastIndexOf(".");
    while (lastDotIndex > 0) {
      const candidate = reference.slice(0, lastDotIndex);
      if (tokens.has(candidate)) {
        this.parentLookupCache.set(reference, candidate);
        return candidate;
      }
      lastDotIndex = reference.lastIndexOf(".", lastDotIndex - 1);
    }
    this.parentLookupCache.set(reference, null);
    return void 0;
  }
  addVirtualChild(parent, child) {
    this.addToSetMap(this.virtualChildren, parent, child);
  }
  getVirtualChildren(parent) {
    const children = this.virtualChildren.get(parent);
    return children ? new Set(children) : /* @__PURE__ */ new Set();
  }
  getAndRemoveVirtualChildren(parent) {
    const children = this.virtualChildren.get(parent);
    if (!children) return /* @__PURE__ */ new Set();
    this.virtualChildren.delete(parent);
    return children;
  }
  removeVirtualChildren(parent) {
    this.virtualChildren.delete(parent);
  }
  getReadyPrefixes() {
    return Array.from(this.activePrefixes.keys()).filter((prefix) => {
      const pending = this.activePrefixes.get(prefix);
      return pending && pending.size === 0;
    });
  }
  clearCaches() {
    this.directChildrenCache.clear();
    this.parentLookupCache.clear();
  }
  addToSetMap(map, key, value) {
    let set = map.get(key);
    if (!set) {
      set = /* @__PURE__ */ new Set();
      map.set(key, set);
    }
    set.add(value);
  }
  toSymbol(value) {
    if (value === void 0) return void 0;
    if (value === null) return new NullSymbol(this.config);
    if (isTokenscriptSymbol(value)) return value;
    return new StringSymbol(String(value), this.config);
  }
};

// src/processor/resolver/ReadinessTracker.ts
var ReadinessTracker = class {
  constructor() {
    this.readyCache = /* @__PURE__ */ new Map();
  }
  /**
   * Check if a token is ready to be resolved.
   * Results are cached until marked dirty.
   */
  isReady(tokenName, dependencyTracker) {
    if (!this.readyCache.has(tokenName)) {
      const ready = dependencyTracker.isTokenReady(tokenName);
      this.readyCache.set(tokenName, ready);
      return ready;
    }
    const cached = this.readyCache.get(tokenName);
    return cached ?? false;
  }
  /**
   * Mark a token's readiness state as dirty after a dependency change
   */
  markDirty(tokenName) {
    this.readyCache.delete(tokenName);
  }
  /**
   * Clear all cached state (e.g., for testing)
   */
  clearCache() {
    this.readyCache.clear();
  }
};

// src/processor/resolver/ResolutionNotifier.ts
var ResolutionNotifier = class {
  constructor(dependencyTracker, prefixManager, readinessTracker, pendingResolution, readyQueue, resolveCallback, buildDictionaryCallback) {
    this.dependencyTracker = dependencyTracker;
    this.prefixManager = prefixManager;
    this.readinessTracker = readinessTracker;
    this.pendingResolution = pendingResolution;
    this.readyQueue = readyQueue;
    this.resolveCallback = resolveCallback;
    this.buildDictionaryCallback = buildDictionaryCallback;
  }
  /**
   * Release all dependencies and prefixes for a token and its flattened children.
   * This is called after a token has been successfully resolved.
   * Triggers cascade resolution of any newly-ready dependents.
   */
  releaseDependencies(tokenName, flattened, referenceCache) {
    this.releaseDependentsFor(tokenName);
    this.releasePrefixesFor(tokenName, referenceCache);
    if (flattened) {
      for (const flatName of flattened) {
        this.releaseDependentsFor(flatName);
        this.releasePrefixesFor(flatName, referenceCache);
      }
    }
  }
  /**
   * Release dependents waiting for a specific token and add to ready queue
   */
  releaseDependentsFor(name) {
    for (const dependent of this.dependencyTracker.getTokenDependentsIterable(name)) {
      if (this.pendingResolution.has(dependent)) continue;
      this.dependencyTracker.removeTokenDependency(dependent, name);
      this.readinessTracker.markDirty(dependent);
      if (this.readinessTracker.isReady(dependent, this.dependencyTracker)) {
        this.readyQueue.add(dependent);
      }
    }
  }
  /**
   * Release prefixes that may now be complete after a token resolution
   */
  releasePrefixesFor(name, referenceCache) {
    const readyPrefixes = this.prefixManager.markTokenResolved(name);
    if (readyPrefixes.length === 0) return;
    for (const prefix of readyPrefixes) {
      this.releasePrefixDependents(prefix, referenceCache);
    }
  }
  /**
   * Release tokens waiting for a specific prefix and add to ready queue
   */
  releasePrefixDependents(prefix, referenceCache) {
    this.buildDictionaryCallback(prefix, referenceCache);
    for (const tokenName of this.dependencyTracker.getTokensWaitingForPrefixIterable(prefix)) {
      if (this.pendingResolution.has(tokenName)) continue;
      this.dependencyTracker.removePrefixDependency(tokenName, prefix);
      this.readinessTracker.markDirty(tokenName);
      if (this.readinessTracker.isReady(tokenName, this.dependencyTracker)) {
        this.readyQueue.add(tokenName);
      }
    }
  }
};
var SelectedTokenSetsObjectSchema = type("Record<string, 'enabled' | 'source'>");
var SelectedTokenSetsArraySchema = type({
  id: "string",
  status: "'enabled' | 'source'"
}).array();
var SelectedTokenSetsSchema = type([
  SelectedTokenSetsObjectSchema,
  "|",
  SelectedTokenSetsArraySchema
]);
var ThemeSchema = type({
  name: "string",
  selectedTokenSets: SelectedTokenSetsSchema,
  "figmaCollectionId?": "string",
  "figmaModeId?": "string",
  "group?": "string"
});
var ThemesArraySchema = ThemeSchema.array();
var selectTheme = (themes, themeName) => {
  return themes.find((theme) => theme.name === themeName);
};
var resolveThemes = (jsonFiles) => {
  const themesFile = jsonFiles.$themes;
  if (themesFile) {
    if (isObject(themesFile) && "$themes" in themesFile) {
      const themesValue = themesFile.$themes;
      const validatedThemes = ThemesArraySchema(themesValue);
      if (!(validatedThemes instanceof type.errors)) {
        return ["$themes", validatedThemes];
      }
    }
    const validatedAsArray = ThemesArraySchema(themesFile);
    if (!(validatedAsArray instanceof type.errors)) {
      return ["$themes", validatedAsArray];
    }
  }
  return void 0;
};
var extractSetNames = (selectedTokenSets) => {
  if (Array.isArray(selectedTokenSets)) {
    return selectedTokenSets.map((set) => set.id);
  }
  return Object.keys(selectedTokenSets);
};

// src/processor/utils/set-processor.ts
function determineSets(jsonFiles, activeSets, activeTheme) {
  if (activeSets) return activeSets;
  if (activeTheme) {
    const resolved = resolveThemes(jsonFiles);
    if (!resolved) {
      throw new Error(`No themes found for theme "${activeTheme}"`);
    }
    const [, themes] = resolved;
    const theme = selectTheme(themes, activeTheme);
    if (!theme) {
      const available = themes.map((t) => t.name).join(", ");
      throw new Error(`Theme "${activeTheme}" not found. Available: ${available}`);
    }
    return extractSetNames(theme.selectedTokenSets);
  }
  const keys = Object.keys(jsonFiles);
  if (keys.length === 1) {
    return keys;
  }
  if (keys.length > 1) {
    throw new Error(`Multiple sets found (${keys.join(", ")}) - specify activeSets or activeTheme`);
  }
  throw new Error("No sets to process");
}
function flattenToTokens(sets, setNames) {
  const tokens = /* @__PURE__ */ new Map();
  for (const setName of setNames) {
    const setData = sets[setName];
    if (!setData) {
      throw new Error(`Token set "${setName}" not found`);
    }
    if (!isObject(setData)) {
      throw new Error(`Token set "${setName}" is not an object`);
    }
    const setTokens = isNested(setData) ? flattenTokensObject(setData, "") : recordToMap(setData);
    for (const [key, value] of setTokens) {
      tokens.set(key, value);
    }
  }
  return tokens;
}

// src/processor/process.ts
function processTokens(tokens, options = {}) {
  const { config, output = "string", builder, objectParsers } = options;
  const tokenMap = tokens instanceof Map ? tokens : flattenToTokens({ tokens }, ["tokens"]);
  return buildTokens(tokenMap, { builder, config, objectParsers, output });
}
function processTokenSets(normalizedFiles, options = {}) {
  const { activeSets, activeTheme, config, output = "string", builder, objectParsers } = options;
  const setNames = determineSets(normalizedFiles, activeSets, activeTheme);
  const tokens = flattenToTokens(normalizedFiles, setNames);
  return buildTokens(tokens, { builder, config, objectParsers, output });
}

// src/processor/resolver/TokenInterpreter.ts
var TokenInterpreter = class {
  constructor(referenceCache, config) {
    this.referenceCache = referenceCache;
    this.config = config;
    this.astNodes = /* @__PURE__ */ new Map();
    this.interpreter = new Interpreter(null, {
      references: this.referenceCache,
      config: this.config
    });
  }
  setTokenAST(tokenName, ast) {
    this.astNodes.set(tokenName, ast);
  }
  getTokenAST(tokenName) {
    return this.astNodes.get(tokenName);
  }
  interpretToken(tokenName, originalValue) {
    const ast = this.astNodes.get(tokenName);
    if (!ast) {
      return originalValue;
    }
    return this.interpretTokenWithAST(tokenName, ast);
  }
  interpretTokenWithAST(_tokenName, ast) {
    try {
      this.interpreter.resetSymbolTable();
      this.interpreter.setAst(ast);
      return this.interpreter.interpret();
    } catch (error) {
      return error instanceof Error ? error : new Error(String(error));
    }
  }
  buildDependencyError(tokenName, dependencies, resolved) {
    for (const dep of dependencies) {
      const depValue = resolved.get(dep);
      if (depValue instanceof Error) {
        return new DependencyError(tokenName, dep, depValue);
      }
    }
    return void 0;
  }
  flattenDictionaryToCache(tokenName, value) {
    if (!(value instanceof DictionarySymbol) || !value.value) {
      return [];
    }
    const flattenedNames = [];
    const entries = value.value;
    for (const [childKey, childValue] of entries) {
      const flattenedKey = `${tokenName}.${childKey}`;
      const clone = this.isSymbolType(childValue) ? childValue.cloneIfMutable() : childValue;
      this.referenceCache.set(flattenedKey, clone);
      flattenedNames.push(flattenedKey);
    }
    return flattenedNames;
  }
  updateReferenceCache(tokenName, value) {
    if (value instanceof Error) return;
    this.referenceCache.set(tokenName, value);
  }
  isSymbolType(value) {
    return Boolean(
      value && typeof value === "object" && typeof value.cloneIfMutable === "function"
    );
  }
};

// src/processor/resolver/TokenResolver.ts
var PrefixResolver = class {
  constructor(tokens, callbacks, config, objectParsers) {
    this.tokens = tokens;
    this.graph = new DependencyGraph();
    this.resolved = /* @__PURE__ */ new Map();
    this.unresolved = /* @__PURE__ */ new Map();
    this.referenceCache = /* @__PURE__ */ new Map();
    this.pendingResolution = /* @__PURE__ */ new Set();
    this.readyQueue = /* @__PURE__ */ new Set();
    // Structured tokens tracking
    this.subFieldPaths = /* @__PURE__ */ new Set();
    this.structuredTokens = /* @__PURE__ */ new Map();
    // Phase state
    this.earlyResolved = [];
    this.callbacks = callbacks;
    this.config = config;
    this.objectParsers = objectParsers;
    this.dependencyTracker = new DependencyTracker();
    this.prefixManager = new PrefixManager(config);
    this.tokenInterpreter = new TokenInterpreter(this.referenceCache, config);
    this.readinessTracker = new ReadinessTracker();
    this.notifier = new ResolutionNotifier(
      this.dependencyTracker,
      this.prefixManager,
      this.readinessTracker,
      this.pendingResolution,
      this.readyQueue,
      (tokenName) => this.resolveSingleToken(tokenName),
      (prefix, cache) => this.buildPrefixDictionary(prefix, cache)
    );
  }
  resolveError(refPath, error, value) {
    this.resolved.set(refPath, error);
    this.callbacks?.onError?.(refPath, error, value);
    this.graph.addNode(refPath, []);
    this.earlyResolved.push(refPath);
    return error;
  }
  earlyResolvePrimitiveToken(tokenName, value) {
    this.resolved.set(tokenName, value);
    this.referenceCache.set(tokenName, value);
    this.callbacks?.onResolve?.(tokenName, value);
    this.graph.addNode(tokenName, []);
    this.earlyResolved.push(tokenName);
  }
  tryParseExpression(refPath, value) {
    try {
      return parseExpression(value);
    } catch (error) {
      const err = error instanceof Error ? error : new Error(String(error));
      return this.resolveError(refPath, err, value);
    }
  }
  processParsedToken(tokenName, ast, dependencies) {
    this.tokenInterpreter.setTokenAST(tokenName, ast);
    if (dependencies.size > 0) {
      this.unresolved.set(tokenName, { ast, dependencies });
    }
    this.graph.addNode(tokenName, dependencies);
    for (const dep of dependencies) {
      if (this.prefixManager.hasPrefix(dep) && !this.tokens.has(dep)) {
        continue;
      }
      if (this.resolved.has(dep)) continue;
      this.dependencyTracker.addTokenDependency(tokenName, dep);
      if (this.tokens.has(dep)) continue;
      const parentToken = this.prefixManager.findParentToken(dep, this.tokens);
      if (parentToken) {
        this.prefixManager.addVirtualChild(parentToken, dep);
        continue;
      }
      if (!this.referenceCache.has(dep)) {
        const error = new Error(`Token '${dep}' not found`);
        this.resolveError(dep, error, "");
      }
    }
  }
  resolve() {
    this.parseAndBuildGraph();
    this.mapPrefixDependencies();
    this.releaseEarlyResolved();
    this.resolveDependencyFreeTokens();
    this.finalizeResolution();
    return {
      graph: this.graph,
      resolved: this.resolved,
      unresolved: this.unresolved,
      subFieldPaths: this.subFieldPaths
    };
  }
  /**
   * Phase 1: Parse and build graph (ResolutionPhase.PARSE_AND_BUILD_GRAPH)
   * - Parse all token values into ASTs
   * - Build dependency graph
   * - Identify and mark early-resolved tokens
   * - Detect missing token dependencies
   * - Handle primitive and structured tokens
   */
  parseAndBuildGraph() {
    this.earlyResolved = [];
    for (const [tokenName, tokenData] of this.tokens.entries()) {
      const tokenValue = getTokenValue(tokenData);
      if (isString(tokenValue) && UNINTERPRETED_KEYWORDS.includes(tokenValue)) {
        const symbol = new StringSymbol(tokenValue, this.config);
        this.earlyResolvePrimitiveToken(tokenName, symbol);
        continue;
      }
      if (isNumber(tokenValue)) {
        this.earlyResolvePrimitiveToken(tokenName, new NumberSymbol(tokenValue, this.config));
        continue;
      }
      if (isBoolean(tokenValue)) {
        this.earlyResolvePrimitiveToken(tokenName, new BooleanSymbol(tokenValue, this.config));
        continue;
      }
      if (isNull(tokenValue)) {
        this.earlyResolvePrimitiveToken(tokenName, new NullSymbol(this.config));
        continue;
      }
      if (isObject(tokenValue) || isArray(tokenValue)) {
        this.handleStructuredToken(tokenName, setTokenValue(tokenData));
        continue;
      }
      const tokenValueStr = String(tokenValue);
      const parseResult = this.tryParseExpression(tokenName, tokenValueStr);
      if (parseResult instanceof Error) {
        continue;
      }
      const { ast, parser } = parseResult;
      if (!ast) {
        this.earlyResolvePrimitiveToken(tokenName, "");
        continue;
      }
      this.prefixManager.addTokenToPrefix(tokenName);
      this.processParsedToken(tokenName, ast, parser.requiredReferences);
    }
  }
  handleStructuredToken(tokenName, tokenData) {
    const tokenValue = tokenData.$value;
    this.structuredTokens.set(tokenName, tokenData);
    const stringFields = extractStringFields(tokenValue, tokenName);
    if (stringFields.size === 0) {
      const tokenType = tokenData.$type || "unknown";
      const tokenSymbol = createTokenSymbol(tokenValue, tokenType, this.config, this.objectParsers);
      this.resolved.set(tokenName, tokenSymbol);
      this.referenceCache.set(tokenName, tokenSymbol);
      this.callbacks?.onResolve?.(tokenName, tokenSymbol);
      this.graph.addNode(tokenName, []);
      this.earlyResolved.push(tokenName);
      return;
    }
    for (const [fieldPath, fieldValue] of stringFields) {
      this.subFieldPaths.add(fieldPath);
      const parseResult = this.tryParseExpression(fieldPath, fieldValue);
      if (parseResult instanceof Error) {
        continue;
      }
      const { ast, parser } = parseResult;
      if (!ast) {
        this.earlyResolvePrimitiveToken(fieldPath, "");
        continue;
      }
      this.processParsedToken(fieldPath, ast, parser.requiredReferences);
    }
    const subFieldDeps = Array.from(stringFields.keys());
    this.graph.addNode(tokenName, subFieldDeps);
    for (const dep of subFieldDeps) {
      this.dependencyTracker.addTokenDependency(tokenName, dep);
    }
    this.unresolved.set(tokenName, {
      ast: null,
      dependencies: new Set(subFieldDeps)
    });
  }
  /**
   * Phase 2: Map prefix dependencies (ResolutionPhase.MAP_PREFIX_DEPENDENCIES)
   * - Identify which tokens depend on prefixes
   * - Activate prefix resolution tracking
   * - Mark prefix dependencies for later resolution
   */
  mapPrefixDependencies() {
    for (const [tokenName, unresolved] of this.unresolved.entries()) {
      for (const dep of unresolved.dependencies) {
        if (this.prefixManager.hasPrefix(dep) && !this.tokens.has(dep)) {
          this.prefixManager.activatePrefix(dep);
          this.dependencyTracker.addPrefixDependency(tokenName, dep);
        }
      }
    }
  }
  /**
   * Phase 3: Release early resolved (ResolutionPhase.RELEASE_EARLY_RESOLVED)
   * - Notify dependents of early-resolved tokens
   * - Release prefix dependencies waiting for these tokens
   * - Trigger cascade resolution of dependent tokens
   */
  releaseEarlyResolved() {
    for (const tokenName of this.earlyResolved) {
      this.notifyResolution(tokenName);
    }
  }
  /**
   * Phase 4: Resolve dependency-free tokens (ResolutionPhase.RESOLVE_DEPENDENCY_FREE)
   * - Seed ready queue with initially dependency-free tokens
   * - Process queue in event-driven manner (cascade resolution)
   * - Queue is populated by ResolutionNotifier when dependencies are released
   */
  resolveDependencyFreeTokens() {
    const allTokens = /* @__PURE__ */ new Set([...this.tokens.keys(), ...this.subFieldPaths]);
    for (const tokenName of allTokens) {
      if (this.resolved.has(tokenName)) continue;
      if (this.readinessTracker.isReady(tokenName, this.dependencyTracker)) {
        this.readyQueue.add(tokenName);
      }
    }
    while (this.readyQueue.size > 0) {
      const tokenName = this.readyQueue.values().next().value;
      this.readyQueue.delete(tokenName);
      this.resolveSingleToken(tokenName);
    }
  }
  resolveSingleToken(tokenName) {
    if (this.resolved.has(tokenName)) return;
    this.pendingResolution.add(tokenName);
    if (this.structuredTokens.has(tokenName)) {
      this.resolveStructuredToken(tokenName);
      this.pendingResolution.delete(tokenName);
      return;
    }
    if (this.subFieldPaths.has(tokenName)) {
      const ast = this.tokenInterpreter.getTokenAST(tokenName);
      if (ast) {
        const unresolved2 = this.unresolved.get(tokenName);
        const dependencyError2 = unresolved2 ? this.tokenInterpreter.buildDependencyError(
          tokenName,
          unresolved2.dependencies,
          this.resolved
        ) : void 0;
        if (dependencyError2) {
          this.resolved.set(tokenName, dependencyError2);
          this.callbacks?.onError?.(tokenName, dependencyError2, "");
        } else {
          const tokenValue2 = this.tokenInterpreter.interpretTokenWithAST(tokenName, ast);
          this.resolved.set(tokenName, tokenValue2);
          if (tokenValue2 instanceof Error) {
            this.callbacks?.onError?.(tokenName, tokenValue2, "");
          } else {
            this.callbacks?.onResolve?.(tokenName, tokenValue2);
            this.tokenInterpreter.updateReferenceCache(tokenName, tokenValue2);
          }
        }
      }
      this.unresolved.delete(tokenName);
      this.notifyResolution(tokenName);
      this.pendingResolution.delete(tokenName);
      return;
    }
    const originalValue = this.tokens.get(tokenName);
    if (originalValue === void 0) return;
    const tokenValueStr = String(getTokenValue(originalValue));
    const unresolved = this.unresolved.get(tokenName);
    const dependencyError = unresolved ? this.tokenInterpreter.buildDependencyError(
      tokenName,
      unresolved.dependencies,
      this.resolved
    ) : void 0;
    let tokenValue;
    if (dependencyError) {
      tokenValue = dependencyError;
      this.resolved.set(tokenName, dependencyError);
      this.callbacks?.onError?.(tokenName, dependencyError, tokenValueStr);
    } else {
      tokenValue = this.tokenInterpreter.interpretToken(tokenName, tokenValueStr);
      this.resolved.set(tokenName, tokenValue);
      if (tokenValue instanceof Error) {
        this.callbacks?.onError?.(tokenName, tokenValue, tokenValueStr);
      } else {
        this.callbacks?.onResolve?.(tokenName, tokenValue);
        this.tokenInterpreter.updateReferenceCache(tokenName, tokenValue);
      }
    }
    const flattened = this.tokenInterpreter.flattenDictionaryToCache(tokenName, tokenValue);
    this.resolveVirtualChildren(tokenName, flattened);
    this.notifyResolution(tokenName, flattened);
    this.unresolved.delete(tokenName);
    this.pendingResolution.delete(tokenName);
  }
  /**
   * Resolve a structured token by assembling resolved sub-fields
   */
  resolveStructuredToken(tokenName) {
    const tokenData = this.structuredTokens.get(tokenName);
    if (!tokenData) return;
    const originalValue = tokenData.$value;
    const stringFields = extractStringFields(originalValue, tokenName);
    const resolvedFields = /* @__PURE__ */ new Map();
    let hasError = false;
    for (const [fieldPath] of stringFields) {
      const fieldValue = this.resolved.get(fieldPath);
      if (fieldValue === void 0) {
        const error = new Error(`Sub-field '${fieldPath}' not resolved`);
        this.resolved.set(tokenName, error);
        this.callbacks?.onError?.(tokenName, error, String(originalValue));
        hasError = true;
        break;
      }
      if (fieldValue instanceof Error) {
        this.resolved.set(tokenName, fieldValue);
        this.callbacks?.onError?.(tokenName, fieldValue, String(originalValue));
        hasError = true;
        break;
      }
      resolvedFields.set(fieldPath, fieldValue);
    }
    if (!hasError) {
      const assembled = assembleStructuredToken(tokenName, resolvedFields, originalValue);
      const tokenType = tokenData.$type || "unknown";
      const tokenSymbol = createTokenSymbol(assembled, tokenType, this.config, this.objectParsers);
      this.resolved.set(tokenName, tokenSymbol);
      this.referenceCache.set(tokenName, tokenSymbol);
      this.callbacks?.onResolve?.(tokenName, tokenSymbol);
    }
    this.unresolved.delete(tokenName);
    this.notifyResolution(tokenName);
  }
  resolveVirtualChildren(parent, flattened) {
    const children = this.prefixManager.getAndRemoveVirtualChildren(parent);
    if (children.size === 0) return;
    const satisfied = flattened.length > 0 ? new Set(flattened) : null;
    const parentValue = this.resolved.get(parent);
    for (const child of children) {
      if (satisfied?.has(child) || this.referenceCache.has(child) || this.resolved.has(child)) {
        continue;
      }
      const error = parentValue instanceof Error ? new DependencyError(child, parent, parentValue) : new Error(`Token '${child}' not found`);
      this.resolved.set(child, error);
      this.callbacks?.onError?.(child, error, "");
    }
  }
  notifyResolution(name, flattened) {
    this.notifier.releaseDependencies(name, flattened, this.referenceCache);
  }
  /**
   * Helper for ResolutionNotifier to build prefix dictionaries
   */
  buildPrefixDictionary(prefix, cache) {
    const dictionary = this.prefixManager.buildPrefixDictionary(prefix, cache);
    if (dictionary) {
      cache.set(prefix, dictionary);
    }
  }
  /**
   * Phase 5: Finalize resolution (ResolutionPhase.FINALIZE)
   * - Handle any true stragglers not caught by event-driven phase
   * - Generate errors for unresolved tokens with dependency issues
   * - Check for circular dependencies
   */
  finalizeResolution() {
    const unresolvedTokens = [];
    for (const tokenName of this.tokens.keys()) {
      const originalValue = this.tokens.get(tokenName);
      if (originalValue === void 0 || this.resolved.has(tokenName)) continue;
      const tokenValueStr = String(getTokenValue(originalValue));
      const unresolved = this.unresolved.get(tokenName);
      if (unresolved) {
        const dependencyError = this.tokenInterpreter.buildDependencyError(
          tokenName,
          unresolved.dependencies,
          this.resolved
        );
        if (dependencyError) {
          this.resolved.set(tokenName, dependencyError);
          this.callbacks?.onError?.(tokenName, dependencyError, tokenValueStr);
          this.resolveVirtualChildren(tokenName, []);
          this.notifyResolution(tokenName);
          this.unresolved.delete(tokenName);
          continue;
        }
      }
      unresolvedTokens.push(tokenName);
    }
    if (unresolvedTokens.length > 0) {
      throw new Error(
        `Detected circular dependency or unresolved prefixes: ${unresolvedTokens.join(", ")}`
      );
    }
  }
};
var TokenResolver = class {
  processTokens(tokens, callbacks, config, objectParsers) {
    const resolver = new PrefixResolver(tokens, callbacks, config, objectParsers);
    return resolver.resolve();
  }
  build(tokens, config, objectParsers) {
    const output = /* @__PURE__ */ new Map();
    const errors = /* @__PURE__ */ new Map();
    let subFieldPaths;
    const callbacks = {
      onResolve: (tokenName, value) => {
        output.set(tokenName, value);
      },
      onError: (tokenName, error, originalValue) => {
        output.set(tokenName, originalValue);
        errors.set(tokenName, error);
      }
    };
    const result = this.processTokens(tokens, callbacks, config, objectParsers);
    subFieldPaths = result.subFieldPaths;
    if (subFieldPaths && subFieldPaths.size > 0) {
      for (const subFieldPath of subFieldPaths) {
        output.delete(subFieldPath);
        errors.delete(subFieldPath);
      }
    }
    return {
      ...result,
      tokens: output,
      errors
    };
  }
};

// src/processor/builders/base.ts
function serializeInterpreterResult(value) {
  if (isString(value)) return value;
  if (isNull(value)) return null;
  if (isTokenscriptSymbol(value)) return symbolTypeToJsValue(value);
  return value;
}
function stringifyInterpreterResult(value) {
  if (isString(value)) return value;
  if (isTokenscriptSymbol(value)) return value.toString();
  return String(value);
}
function buildTokens(tokens, options) {
  const {
    config,
    output = "string",
    builder = new MapBuilder(output),
    objectParsers
  } = options ?? {};
  const processor = new TokenResolver();
  const errors = /* @__PURE__ */ new Map();
  const tokensMapBuilder = builder instanceof MapBuilder ? builder : new MapBuilder(output);
  const callbacks = {
    onResolve: (tokenName, value) => {
      builder.onResolve(tokenName, value);
      if (!(builder instanceof MapBuilder)) tokensMapBuilder.onResolve(tokenName, value);
    },
    onError: (tokenName, error, originalValue) => {
      builder.onError(tokenName, error, originalValue);
      errors.set(tokenName, error);
      if (!(builder instanceof MapBuilder))
        tokensMapBuilder.onError(tokenName, error, originalValue);
    }
  };
  const result = processor.processTokens(tokens, callbacks, config, objectParsers);
  let tokensMap = tokensMapBuilder.getResult();
  const builderOutput = builder.getResult();
  if (result.subFieldPaths && result.subFieldPaths.size > 0) {
    tokensMap = new Map(tokensMap);
    for (const subFieldPath of result.subFieldPaths) {
      tokensMap.delete(subFieldPath);
      errors.delete(subFieldPath);
    }
  }
  return {
    ...result,
    tokens: tokensMap,
    output: builderOutput,
    errors
  };
}

// src/processor/builders/MapBuilder.ts
var MapBuilder = class {
  constructor(outputFormat = "string") {
    this.outputFormat = outputFormat;
    this.name = "map";
    this.result = /* @__PURE__ */ new Map();
    this.successfullyResolved = /* @__PURE__ */ new Map();
  }
  onResolve(tokenName, value) {
    this.successfullyResolved.set(tokenName, value);
    if (this.outputFormat === "symbols") {
      this.result.set(tokenName, value);
    } else {
      this.result.set(tokenName, stringifyInterpreterResult(value));
    }
  }
  onError(tokenName, _error, originalValue) {
    this.result.set(tokenName, originalValue);
  }
  getResult() {
    return this.result;
  }
  getResolvedTokens() {
    return this.successfullyResolved;
  }
};

// src/processor/builders/ObjectBuilder.ts
function setNestedValue(target, path, value) {
  if (path.length === 0) {
    return;
  }
  const segments = path.split(".");
  let cursor = target;
  for (let i = 0; i < segments.length; i++) {
    const key = segments[i];
    const isLast = i === segments.length - 1;
    if (isLast) {
      cursor[key] = value;
      return;
    }
    if (!isObject(cursor[key])) {
      cursor[key] = {};
    }
    cursor = cursor[key];
  }
}
var NestedObjectBuilder = class {
  constructor() {
    this.name = "nested";
    this.result = {};
  }
  onResolve(tokenName, value) {
    const serialized = serializeInterpreterResult(value);
    if (typeof serialized !== "undefined") {
      setNestedValue(this.result, tokenName, serialized);
    }
  }
  onError(tokenName, _error, originalValue) {
    setNestedValue(this.result, tokenName, originalValue);
  }
  getResult() {
    return this.result;
  }
};
var FlatObjectBuilder = class {
  constructor() {
    this.name = "flat";
    this.result = {};
  }
  onResolve(tokenName, value) {
    let didFlatten = false;
    flattenChildrenObject(value, tokenName, (key, val) => {
      didFlatten = true;
      this.result[key] = serializeInterpreterResult(val);
    });
    if (!didFlatten) {
      const serialized = serializeInterpreterResult(value);
      if (typeof serialized !== "undefined") {
        this.result[tokenName] = serialized;
      }
    }
  }
  onError(tokenName, _error, originalValue) {
    this.result[tokenName] = originalValue;
  }
  getResult() {
    return this.result;
  }
};

export { DependencyError, FlatObjectBuilder, MapBuilder, NestedObjectBuilder, TokenResolver, defaultObjectParsers, flattenChildrenMap, flattenChildrenObject, numberWithUnitParser, processTokenSets, processTokens };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map