All files / kernel-agents-repl/src/strategies/repl/parse identifiers.ts

96.42% Statements 27/28
93.75% Branches 15/16
100% Functions 7/7
96.29% Lines 26/27

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    2x 101x   1x     100x     100x 31x     69x 258x     63x 63x     195x 33x         69x                             2x     69x 62x   198x   68x 69x 14x 5x     5x   69x     62x     5x   2x      
import type { SyntaxNode } from 'tree-sitter';
 
const extractIdentifiers = (pattern?: SyntaxNode): string[] => {
  if (!pattern) {
    // This would be a tree-sitter error.
    throw new Error('Internal: Declarator missing pattern');
  }
 
  const identifiers: string[] = [];
 
  // Handle the case where the pattern itself is an identifier (simple cases like 'const x = 1')
  if (pattern.type === 'identifier') {
    return [pattern.text];
  }
 
  for (const child of pattern.children) {
    switch (child.type) {
      case 'identifier':
      case 'shorthand_property_identifier_pattern':
        identifiers.push(child.text);
        break;
      default:
        // Recursively handle other pattern types
        if (child.type.endsWith('_pattern')) {
          identifiers.push(...extractIdentifiers(child));
        }
    }
  }
 
  return identifiers;
};
 
/**
 * Given a declaration, extract the names of the declared identifiers.
 * These names cover the keys of the namespace delta resulting from evaluation.
 *
 * @param declaration - The declaration to extract the names from.
 *   A declaration is a top level node which is also one of the following:
 *     - a const statement
 *     - a let statement
 *     - a var statement
 *     - a function declaration
 * @returns The names of the identifiers declared in the declaration.
 */
export const extractNamesFromDeclaration = (
  declaration: SyntaxNode,
): string[] => {
  const variableIdentifiers = ({ children }: SyntaxNode): string[] =>
    children
      .filter(({ type }) =>
        ['variable_declarator', 'declarator'].includes(type),
      )
      .flatMap(({ children: [pattern] }) => extractIdentifiers(pattern));
  const functionIdentifier = ({ children }: SyntaxNode): string => {
    const identifier = children.find((child) => child.type === 'identifier');
    Iif (!identifier) {
      throw new Error('Internal: Function declaration missing identifier');
    }
    return identifier.text;
  };
  switch (declaration.type) {
    case 'lexical_declaration':
    case 'variable_declaration':
      return variableIdentifiers(declaration);
    case 'function_declaration':
    case 'generator_function_declaration':
      return [functionIdentifier(declaration)];
    default:
      throw new Error(`Unknown declaration type: ${declaration.type}`);
  }
};