GenUiSurfaceGraph.of constructor

GenUiSurfaceGraph.of(
  1. SurfaceDefinition definition
)

Reads the graph out of definition.

Implementation

factory GenUiSurfaceGraph.of(SurfaceDefinition definition) {
  final Set<String> ids = definition.components.keys.toSet();
  final children = <String, Set<String>>{};
  final boundPaths = <String, Set<String>>{};

  // Which of a component's children arrived through a template, and over
  // which list: a templated child reads its properties inside that list's
  // row, so its paths resolve against it rather than against the root.
  final templates = <String, Map<String, String>>{};
  final rawPaths = <String, Set<String>>{};

  for (final Component component in definition.components.values) {
    final found = <String>{};
    final paths = <String>{};
    final repeated = <String, String>{};
    _scan(component.properties, ids, found, paths, repeated);
    children[component.id] = found;
    rawPaths[component.id] = paths;
    if (repeated.isNotEmpty) templates[component.id] = repeated;
  }

  final order = <String>[];
  final seen = <String>{};
  final cyclic = <String>{};
  final onStack = <String>{};
  final bases = <String, String>{genUiRootComponentId: '/'};
  void walk(String id) {
    if (!ids.contains(id)) return;
    if (onStack.contains(id)) {
      cyclic.add(id);
      return;
    }
    if (!seen.add(id)) return;
    order.add(id);
    onStack.add(id);
    final String base = bases[id] ?? '/';
    for (final String child in children[id]!) {
      final String? over = templates[id]?[child];
      // A component reached two ways keeps the first base it was given.
      bases[child] ??= over == null
          ? base
          : '${_resolve(base, over)}/$genUiRowWildcard';
      walk(child);
    }
    onStack.remove(id);
  }

  walk(genUiRootComponentId);

  for (final MapEntry<String, Set<String>> entry in rawPaths.entries) {
    final String base = bases[entry.key] ?? '/';
    boundPaths[entry.key] = <String>{
      for (final String path in entry.value) _resolve(base, path),
    };
  }

  return GenUiSurfaceGraph._(
    definition: definition,
    children: children,
    boundPaths: boundPaths,
    order: List<String>.unmodifiable(order),
    unreachable: Set<String>.unmodifiable(
      ids.where((String id) => !seen.contains(id)).toSet(),
    ),
    cyclic: Set<String>.unmodifiable(cyclic),
  );
}