npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

escope-id

v0.0.5

Published

Analyze the definition of identifier based on estree

Downloads

5

Readme

简介

基于estree,分析作用域中标识符的定义。

安装

npm i escope-id

导出函数

import { analyze, createScopeMap } from 'escope-id';

analyze

接收一个类型为'Program'的ast结点,构造作用域并分析其中的标识符。

类型

import type {
  Class,
  ForInStatement,
  ForOfStatement,
  ForStatement,
  BlockStatement,
  Function as ESTFunction,
  Program,
  CatchClause,
  WithStatement,
  SwitchStatement,
} from 'estree'

interface IdentifierInScope {
  name: string,
  /**
   * variable类型对应使用const、let或var声明的变量
   * function类型对应函数声明
   * class类型对应类声明
   * argument类型对应函数的参数,或者catch语句的参数
   * import类型对应使用导入语句声明的变量
   * unknown类型对应那些即不在当前作用域声明也不在某个祖先作用域声明的变量
   */
  type: 'variable' | 'function' | 'class' | 'argument' | 'import' | 'unknown',
  /** 是否在当前作用域中声明的 */
  local: boolean,
  /** 该标识符的声明是否会被提升 */
  hoisted: boolean
}

type ScopeNode = Program |
  Class | 
  ESTFunction |
  BlockStatement |
  ForStatement |
  ForInStatement |
  ForOfStatement |
  CatchClause |
  WithStatement |
  SwitchStatement

class Scope {
  public readonly node: ScopeNode
  public readonly parent: Scope | null; // 只有根级别的作用域的parent为null
  public readonly children: Scope[];
  /** @readonly */
  public identifiers: IdentifierInScope

  /** 根据名称查询一个标识符 */
  public find(name: string): IdentifierInScope // 标识符的name在当前作用域中是唯一的
  /**
   * 根据名称来判断对应标识符在何处声明
   * 如果目标标识符在当前作用域中不存在,返回'unknown';
   * 如果存在且它的'local'属性值为true,返回'local';
   * 如果存在且它的'local'属性值为false,type属性值为'unknown'时返回'global否则返回'ancestral'。
   * */
  public where(name: string): 'unknown' | 'local' | 'ancestral' | 'glboal'

  /** 根据一个ast结点来获取其产生的作用域 */
  public acquire(node: ScopeNode): Scope | null
}

使用

import { parse } from 'acorn';
import { analyze } from 'escope-id';
const script = 'const a = 10; console.log(a)';
const topScope = analyze(parse(script))
console.log(topScope.identifiers)
// [
//   { name: 'a', type: 'variable', hoisted: false, local: true },
//   { name: 'console', type: 'unknown', hoisted: false, local: false }
// ]
console.log(topScope.where('console')) // 'global'

createScopeMap

Scope类的方法acquire的替代品,该法会通过遍历子结点来获取目标值, 而createScopeMap函数会创建一个映射到目标值的WeakMap,并返回一个函数用于查询,查询速度较快。

使用

import { parse } from 'acorn';
import { createScopeMap } from 'escope-id';
const script = 'const a = 10; console.log(a)';
const topScope = analyze(parse(script))
const program = topScope.node
const acquire = createScopeMap(topScope)
console.log(acquire(program) === topScope) // true