or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

configuration.mdformatting-rules.mdindex.mdrequirement-rules.mdutilities.mdvalidation-rules.md
tile.json

utilities.mddocs/

Utility Functions

Helper functions for Flow file detection, AST processing, and rule implementation support used internally by the plugin and available for custom rule development.

Capabilities

Flow File Detection

Functions that determine whether files should be processed by Flow type checking rules.

function checkFlowFileAnnotation(ruleCreate: RuleCreateFunction): RuleCreateFunction;
function isFlowFile(context: ESLintContext): boolean;
function isNoFlowFile(context: ESLintContext): boolean;
function isFlowFileAnnotation(comment: string): boolean;
function isNoFlowFileAnnotation(comment: string, strict?: boolean): boolean;

type RuleCreateFunction = (context: ESLintContext) => RuleListener;

Usage Examples:

// checkFlowFileAnnotation - wrapper for rules
const originalRule = {
  create: (context) => ({
    FunctionDeclaration(node) {
      // Rule implementation
    }
  })
};

// Wrapped rule only runs on Flow files
const wrappedRule = {
  ...originalRule,
  create: checkFlowFileAnnotation(originalRule.create)
};

// isFlowFile - check if current file has Flow annotation
function create(context) {
  if (!isFlowFile(context)) {
    return {};  // Skip non-Flow files
  }
  
  return {
    TypeAnnotation(node) {
      // Process Flow type annotations
    }
  };
}

// isFlowFileAnnotation - validate annotation format
isFlowFileAnnotation('// @flow');        // true
isFlowFileAnnotation('/* @flow */');     // true  
isFlowFileAnnotation('// @flow strict'); // true
isFlowFileAnnotation('// @noflow');      // false

// isNoFlowFileAnnotation - validate @noflow annotation format
isNoFlowFileAnnotation('// @noflow');      // true
isNoFlowFileAnnotation('/* @noflow */');   // true
isNoFlowFileAnnotation('// @flow');        // false
isNoFlowFileAnnotation('// @noflow', true); // true - strict mode

AST Navigation

Functions for navigating and extracting information from Abstract Syntax Tree nodes.

function getParameterName(parameter: Parameter): string;
function getTokenAfterParens(context: ESLintContext, node: ASTNode): Token | null;
function getTokenBeforeParens(context: ESLintContext, node: ASTNode): Token | null;
function iterateFunctionNodes(node: ASTNode, callback: (functionNode: FunctionNode) => void): void;

interface Parameter {
  type: string;
  name?: string;
  left?: Parameter;  // For destructuring
  key?: ASTNode;     // For object patterns
}

interface Token {
  type: string;
  value: string;
  range: [number, number];
}

Usage Examples:

// getParameterName - extract parameter names from complex patterns
getParameterName({type: 'Identifier', name: 'user'});  // 'user'
getParameterName({type: 'RestElement', argument: {name: 'args'}}); // 'args'
getParameterName({type: 'ObjectPattern', properties: [...]}); // 'object'

// getTokenAfterParens - find token after parentheses
function processFunction(context, node) {
  const tokenAfter = getTokenAfterParens(context, node);
  if (tokenAfter && tokenAfter.value === ':') {
    // Function has return type annotation
  }
}

// iterateFunctionNodes - process all function nodes in AST
function create(context) {
  return {
    Program(programNode) {
      iterateFunctionNodes(programNode, (functionNode) => {
        // Process each function in the program
        validateFunctionTypeAnnotations(functionNode);
      });
    }
  };
}

String Processing

Functions for string manipulation and matching used in rule implementations.

function fuzzyStringMatch(needle: string, haystack: string): boolean;
function quoteName(name: string): string;

interface StringMatchOptions {
  caseSensitive?: boolean;
  threshold?: number;
}

Usage Examples:

// fuzzyStringMatch - find approximate string matches
fuzzyStringMatch('funcion', 'function');  // true - close match
fuzzyStringMatch('lenght', 'length');     // true - common typo
fuzzyStringMatch('abc', 'xyz');          // false - no match

// Used in rule suggestions:
function create(context) {
  return {
    Identifier(node) {
      if (node.name === 'lenght') {
        context.report({
          node,
          message: `Unknown identifier "${node.name}". Did you mean "length"?`,
          fix: (fixer) => fixer.replaceText(node, 'length')
        });
      }
    }
  };
}

// quoteName - add quotes around identifiers when needed
quoteName('validName');      // 'validName'
quoteName('invalid-name');   // '"invalid-name"'
quoteName('123invalid');     // '"123invalid"'
quoteName('class');          // '"class"' (reserved word)

Spacing and Formatting

Utility functions for consistent spacing and formatting fixes.

const spacingFixers = {
  stripSpacesBefore: (node: ASTNode, spaces: number) => (fixer: RuleFixer) => Fix;
  stripSpacesAfter: (node: ASTNode, spaces: number) => (fixer: RuleFixer) => Fix;
  addSpaceBefore: (node: ASTNode) => (fixer: RuleFixer) => Fix;
  addSpaceAfter: (node: ASTNode) => (fixer: RuleFixer) => Fix;
  replaceWithSpaceBefore: (node: ASTNode, spaces: number) => (fixer: RuleFixer) => Fix;
  replaceWithSpaceAfter: (node: ASTNode, spaces: number) => (fixer: RuleFixer) => Fix;
  stripSpaces: (direction: 'before' | 'after', node: ASTNode, spaces: number) => (fixer: RuleFixer) => Fix;
  addSpace: (direction: 'before' | 'after', node: ASTNode) => (fixer: RuleFixer) => Fix;
  replaceWithSpace: (direction: 'before' | 'after', node: ASTNode, spaces: number) => (fixer: RuleFixer) => Fix;
};

interface Fix {
  range: [number, number];
  text: string;
}

Usage Examples:

// spacingFixers - consistent spacing fixes
function create(context) {
  return {
    TypeAnnotation(node) {
      const colonToken = context.getSourceCode().getTokenBefore(node);
      
      if (needsSpaceAfterColon(colonToken)) {
        context.report({
          node,
          message: 'Missing space after type colon',
          fix: spacingFixers.addSpaceAfter(colonToken)
        });
      }
      
      if (hasExtraSpaceBefore(colonToken)) {
        context.report({
          node,
          message: 'Extra space before type colon',
          fix: spacingFixers.stripSpacesBefore(colonToken, 1)
        });
      }
    }
  };
}

Built-in Rule Access

Function for accessing built-in ESLint rules for extension or modification.

function getBuiltinRule(ruleName: string): ESLintRule | null;

interface ESLintRule {
  create: RuleCreateFunction;
  meta?: RuleMeta;
}

Usage Examples:

// getBuiltinRule - extend existing ESLint rules
function create(context) {
  const baseRule = getBuiltinRule('no-unused-expressions');
  
  if (!baseRule) {
    return {};
  }
  
  // Create base rule visitor
  const baseVisitor = baseRule.create(context);
  
  // Extend with Flow-specific logic
  return {
    ...baseVisitor,
    TypeAnnotation(node) {
      // Additional Flow-specific validation
      if (isUnusedTypeAnnotation(node)) {
        context.report({
          node,
          message: 'Unused type annotation'
        });
      }
    }
  };
}

Advanced Usage Patterns

Custom Rule Development

How to use utilities when developing custom Flow type checking rules.

interface CustomRuleOptions {
  checkFlowFiles?: boolean;
  allowPatterns?: string[];
  severity?: 'error' | 'warn';
}

Usage Examples:

// Complete custom rule using utilities
const customFlowRule = {
  meta: {
    docs: {
      description: 'Custom Flow type validation',
      category: 'Possible Errors'
    },
    fixable: 'code',
    schema: [/* options schema */]
  },
  
  create: checkFlowFileAnnotation((context) => {
    // Only runs on Flow files due to wrapper
    
    return {
      FunctionDeclaration(node) {
        // Use utilities for processing
        iterateFunctionNodes(node, (funcNode) => {
          funcNode.params.forEach((param) => {
            const paramName = getParameterName(param);
            
            if (needsTypeAnnotation(param)) {
              const suggestion = fuzzyStringMatch(paramName, 'string') ? 
                'string' : 'any';
                
              context.report({
                node: param,
                message: `Parameter "${paramName}" needs type annotation`,
                fix: (fixer) => {
                  const quotedName = quoteName(paramName);
                  return fixer.insertTextAfter(param, `: ${suggestion}`);
                }
              });
            }
          });
        });
      }
    };
  })
};

Types

interface UtilityFunction {
  (...args: any[]): any;
}

interface ESLintContext {
  getFilename(): string;
  getSourceCode(): SourceCode;
  report(descriptor: ReportDescriptor): void;
  options: any[];
  settings: {
    flowtype?: FlowtypeSettings;
  };
}

interface SourceCode {
  getText(node?: ASTNode): string;
  getTokenBefore(node: ASTNode): Token | null;
  getTokenAfter(node: ASTNode): Token | null;
  getCommentsBefore(node: ASTNode): Comment[];
  getCommentsAfter(node: ASTNode): Comment[];
}

interface Comment {
  type: 'Line' | 'Block';
  value: string;
  range: [number, number];
}

interface RuleListener {
  [nodeType: string]: (node: ASTNode) => void;
}

interface FunctionNode extends ASTNode {
  id: Identifier | null;
  params: Parameter[];
  body: BlockStatement;
  returnType?: TypeAnnotation;
}