Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Peast Laravel Package

mck89/peast

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation: Add to composer.json:

    "require": {
        "mck89/peast": "^1.17"
    }
    

    Run composer install.

  2. First Parse:

    require __DIR__.'/vendor/autoload.php';
    
    $source = 'const x = 1; function foo() { return x; }';
    $ast = \Peast\Peast::latest($source)->parse();
    
    • $ast is now an ESTree node structure (e.g., Program root with VariableDeclaration and FunctionDeclaration children).
  3. Key Classes:

    • \Peast\Peast: Entry point for parsing.
    • \Peast\Traverser: Walk the AST (e.g., find all FunctionDeclaration nodes).
    • \Peast\Query: Select nodes via CSS-like selectors (e.g., Program > FunctionDeclaration).

First Use Case: Extract Function Names

$traverser = new \Peast\Traverser();
$traverser->enterFunctionDeclaration(function (\Peast\Node $node) {
    echo "Found function: {$node->name}\n";
});

$traverser->traverse($ast);

Output:

Found function: foo

Implementation Patterns

1. Parsing with Options

Configure parser behavior (e.g., ECMAScript version, source maps):

$options = [
    'ecmaVersion' => 2020, // ES2020 (default: latest)
    'sourceType'  => 'module', // 'script' or 'module'
    'range'       => true, // Include start/end positions
    'comment'     => true, // Preserve comments
];

$ast = \Peast\Peast::latest($source, $options)->parse();

2. Traversing the AST

Pattern: Use Traverser to modify or analyze nodes.

$traverser = new \Peast\Traverser();
$traverser->enterVariableDeclaration(function (\Peast\Node $node) {
    if ($node->kind === 'const') {
        echo "Constant: {$node->declarations[0]->id->name}\n";
    }
});
$traverser->traverse($ast);

Laravel Integration: Wrap in a service class:

class JSASTService {
    public function parse(string $jsCode): \Peast\Node
    {
        return \Peast\Peast::latest($jsCode)->parse();
    }

    public function findFunctions(\Peast\Node $ast): array
    {
        $traverser = new \Peast\Traverser();
        $functions = [];

        $traverser->enterFunctionDeclaration(function (\Peast\Node $node) use (&$functions) {
            $functions[] = $node->name;
        });
        $traverser->traverse($ast);
        return $functions;
    }
}

3. Querying Nodes

Use Query for selector-based searches (e.g., find all arrow functions):

$query = new \Peast\Query($ast);
$arrowFunctions = $query->find('FunctionDeclaration[async=false][expression=true]');

4. Rendering AST Back to JS

Convert AST to code (e.g., for minification or debugging):

$renderer = new \Peast\Renderer();
$renderedCode = $renderer->render($ast);

5. Handling Comments

Parse and preserve comments:

$options = ['comment' => true];
$ast = \Peast\Peast::latest($source, $options)->parse();

// Access comments via node->leadingComments or node->trailingComments

6. ES Version Targeting

Specify ECMAScript version to avoid parsing unsupported syntax:

// Parse as ES2015 (avoids ES2020+ features)
$ast = \Peast\Peast::version2015($source)->parse();

7. Error Handling

Catch syntax errors gracefully:

try {
    $ast = \Peast\Peast::latest('invalid js {')->parse();
} catch (\Peast\Error $e) {
    echo "Syntax error: {$e->getMessage()} at line {$e->getLine()}";
}

Gotchas and Tips

Pitfalls

  1. Xdebug Nesting Limit:

    • Issue: Deeply nested JS (e.g., recursive functions) triggers Maximum function nesting level errors.
    • Fix: Increase Xdebug setting:
      ini_set('xdebug.max_nesting_level', 1000);
      
      Or disable Xdebug in production.
  2. Unicode Identifiers:

    • Issue: rawName vs. name properties differ for Unicode escapes (e.g., \u0041).
    • Fix: Use $node->rawName for original source representation.
  3. BlockStatement Brackets:

    • Issue: Single-line blocks (e.g., if (x) y) may lose brackets when re-rendered.
    • Fix: Manually ensure brackets in traversal:
      $traverser->enterIfStatement(function (\Peast\Node $node) {
          if (count($node->consequent->body) === 1 && !$node->consequent->body[0] instanceof \Peast\BlockStatement) {
              $node->consequent->body = new \Peast\BlockStatement([$node->consequent->body[0]]);
          }
      });
      
  4. ES Version Mismatches:

    • Issue: Parsing ES2020+ code with ES2015 settings fails silently or throws errors.
    • Fix: Explicitly set ecmaVersion to match your target.
  5. Comment Handling:

    • Issue: Comments are parsed but not automatically preserved in transformations.
    • Fix: Use leadingComments/trailingComments properties and reattach during traversal.
  6. Large Files:

    • Issue: Memory spikes with 1MB+ JS files.
    • Fix: Stream input or parse incrementally (e.g., split by semicolons).

Debugging Tips

  1. Visualize AST: Use var_export($ast, true) or a library like league/container to inspect nodes.

  2. Selector Testing: Test Query selectors incrementally:

    $query = new \Peast\Query($ast);
    var_dump($query->find('FunctionDeclaration')); // Start broad
    
  3. Renderer Quirks:

    • Problem: Rendered code may not match input due to AST normalization (e.g., implicit semicolons).
    • Solution: Compare render($ast) with original source to identify discrepancies.
  4. Performance Profiling: For large ASTs, profile traversal:

    $start = microtime(true);
    $traverser->traverse($ast);
    echo "Traversal time: " . (microtime(true) - $start) . "s";
    

Extension Points

  1. Custom Node Visitors: Extend \Peast\Visitor to add domain-specific logic:

    class MyVisitor extends \Peast\Visitor {
        public function enterFunctionDeclaration(\Peast\Node $node) {
            // Custom logic
        }
    }
    
  2. AST Transformations: Use Traverser to rewrite nodes (e.g., rename variables):

    $traverser = new \Peast\Traverser();
    $traverser->enterIdentifier(function (\Peast\Node $node) {
        if ($node->name === 'oldName') {
            $node->name = 'newName';
        }
    });
    
  3. Plugin Architecture: Encapsulate traversal logic in Laravel service providers:

    // app/Providers/JSASTServiceProvider.php
    public function register() {
        $this->app->singleton(JSASTService::class, function () {
            return new JSASTService();
        });
    }
    
  4. Integration with Laravel Blade: Parse JS in Blade templates:

    // app/Helpers/JSASTHelper.php
    function parseInlineJS(string $js): string {
        $ast = \Peast\Peast::latest($js)->parse();
        // Validate or transform AST
        return $ast->type; // Example: return AST type
    }
    
    @php
        $js = '<script>const x = 1;</script>';
        $astType = parseInlineJS($js);
    @endphp
    

Laravel-Specific Tips

  1. Caching Parsed ASTs: Cache ASTs in Laravel’s cache system:
    $cacheKey = 'js_ast_' . md5($jsCode);
    $ast = Cache::remember($cache
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky