Last 12 weeks · 0 commits
2 of 6 standards met
Have discovered a minor scope bug while testing the integrations on . Also brought up while integrating for Vite's static analysis in https://github.com/vitejs/vite/pull/22850. A following is a AI-assisted write-up: Periscopic 4.0.3 reports the binding identifier of a named as global, even when the class contains no references. It also does not create a scope for the class's self-binding, so references inside the class are reported as global instead of resolving to that binding. Reproduction: https://stackblitz.com/edit/stackblitz-starters-7wcyuezb?file=index.mjs The bare case contains no reference to . Its only identifier is the class name, which is a binding position. Periscopic nevertheless collects that identifier as a reference and reports it as global because there is no declaration owner. The method case contains an actual reference. JavaScript resolves it to the named class expression's inner binding, which is visible within the class and does not leak into the enclosing scope. Periscopic instead reports it as global because it creates no scope containing that binding.
While using analyze in periscopic 4.0.3, the ExportNamedDeclaration path for re-exports creates a child scope and returns early. That early return skips the shared unwind step that restores current_scope to its parent. Result: declarations that come after a re-export at module top level are recorded on the export-created child scope instead of the root scope. Minimal reproduction Using acorn + periscopic: Expected Declarations after the re-export should belong to module root scope (or at least be discoverable from rootScope.find_owner). Actual Declarations after the re-export are attached to the export-created child scope, and rootScope.find_owner for those names returns null. Why this seems to happen In the ExportNamedDeclaration with source branch, current_scope is advanced to a new Scope and the branch returns before the shared unwind logic runs (the context.next + parent restore block). That leaves current_scope on the child for subsequent traversal. Impact Consumers that rely on exact ownership scope identity (not just upward lookup from the current active child) can misclassify bindings declared after re-exports. Potential fix Keep the no-descend behavior for re-export specifiers, but restore current_scope before returning in that branch (or refactor so that branch still executes the shared unwind step).
Repository: Rich-Harris/periscopic. Description: Utility for analyzing scopes belonging to an ESTree-compliant AST Stars: 108, Forks: 10. Primary language: JavaScript. Languages: JavaScript (100%). License: MIT. Latest release: v4.0.3 (4mo ago). Open PRs: 1, open issues: 5. Last activity: 4mo ago. Community health: 42%. Top contributors: Rich-Harris, mrkishi, tanhauhau, ChristianMurphy, benmccann, remcohaszing, milton-alvarenga, dependabot[bot], theoludwig, github-actions[bot].