All files / utils ScopeUtils.ts

100% Statements 14/14
100% Branches 4/4
100% Functions 5/5
100% Lines 14/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125                                                1141x                             1141x 1141x 1141x                 237x                           237x                             591x                                   219x                           331x 331x   331x 255x 255x     331x          
/**
 * Factory functions and type guards for IScopeSymbol.
 *
 * Provides utilities for creating and inspecting C-Next scopes.
 */
import type IScopeSymbol from "../transpiler/types/symbols/IScopeSymbol";
import type TVisibility from "../transpiler/types/TVisibility";
import ESourceLanguage from "./types/ESourceLanguage";
 
class ScopeUtils {
  // ============================================================================
  // Factory Functions
  // ============================================================================
 
  /**
   * Create the global scope with self-reference parent.
   *
   * Global scope has:
   * - name: "" (empty string)
   * - parent: points to itself (self-reference)
   * - scope: points to itself (self-reference)
   */
  static createGlobalScope(): IScopeSymbol {
    // Create a mutable object first to establish self-references
    const global: IScopeSymbol = {
      kind: "scope",
      name: "",
      parent: null as unknown as IScopeSymbol, // Temporary, will be set below
      scope: null as unknown as IScopeSymbol, // Temporary, will be set below
      members: [],
      functions: [],
      variables: [],
      memberVisibility: new Map(),
      sourceFile: "",
      sourceLine: 0,
      sourceLanguage: ESourceLanguage.CNext,
      isExported: true,
    };
    // Set self-references for global scope
    (global as unknown as { parent: IScopeSymbol }).parent = global;
    (global as unknown as { scope: IScopeSymbol }).scope = global;
    return global;
  }
 
  /**
   * Create a named scope with the given parent.
   *
   * Named scopes can be nested (e.g., Outer.Inner).
   */
  static createScope(name: string, parent: IScopeSymbol): IScopeSymbol {
    const scope: IScopeSymbol = {
      kind: "scope",
      name,
      parent,
      scope: parent, // Scope's containing scope is its parent
      members: [],
      functions: [],
      variables: [],
      memberVisibility: new Map(),
      sourceFile: "",
      sourceLine: 0,
      sourceLanguage: ESourceLanguage.CNext,
      isExported: true,
    };
    return scope;
  }
 
  // ============================================================================
  // Type Guards
  // ============================================================================
 
  /**
   * Check if a scope is the global scope.
   *
   * Global scope is identified by:
   * - Empty name ("")
   * - Self-referential parent (parent === scope)
   */
  static isGlobalScope(scope: IScopeSymbol): boolean {
    return scope.name === "" && scope.parent === scope;
  }
 
  // ============================================================================
  // Visibility Utilities
  // ============================================================================
 
  /**
   * ADR-016: Get the default visibility for a scope member based on its type.
   *
   * Member-type-aware defaults reduce boilerplate:
   * - Functions: public by default (API surface)
   * - Variables/types: private by default (internal state)
   *
   * @param isFunction - Whether the member is a function declaration
   * @returns The default visibility for this member type
   */
  static getDefaultVisibility(isFunction: boolean): TVisibility {
    return isFunction ? "public" : "private";
  }
 
  // ============================================================================
  // Path Utilities
  // ============================================================================
 
  /**
   * Get the scope path from outermost to innermost (excluding global scope).
   *
   * For scope "Outer.Inner", returns ["Outer", "Inner"].
   * For global scope, returns [].
   */
  static getScopePath(scope: IScopeSymbol): string[] {
    const path: string[] = [];
    let current = scope;
 
    while (!ScopeUtils.isGlobalScope(current)) {
      path.unshift(current.name);
      current = current.parent;
    }
 
    return path;
  }
}
 
export default ScopeUtils;