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

jinx-rust

v0.1.6

Published

Rust parser

Downloads

4,627

Readme

jinx-rust · GitHub license npm version GitHub Repo stars Twitter Follow

jinx-rust is a Rust parser written in Typescript; it enables the development of Rust Tooling in Typescript.

Example project using jinx-rust: Prettier Rust formatter

Get Started

npm install jinx-rust
import { rs } from "jinx-rust";

const file = rs.parseFile("let leet: u32 = 1337;");

console.log(JSON.stringify(file));

{
  "type": "SourceFile",
  "program": {
    "type": "Program",
    "ast": [
      {
        "type": "LetVariableDeclaration",
        "pattern": { "type": "Identifier", "name": "leet" },
        "typeAnnotation": { "type": "Identifier", "name": "u32" },
        "expression": { "type": "Literal", "kind": 11, "value": "1337" }
      }
    ],
    "danglingAttributes": [],
    "comments": []
  }
}

A tolerant parser for better Rust Tooling

jinx-rust is unstrict by default and tolerates bad syntax

  • Tokens:

    • Missing semicolons
    • Missing commas in some places
    • Whitespace within long tokens
    • Javascript-ey syntax, (currently just === and !==)
    • Unsyntactic parentheses (e.g. RangePattern bounds)
    • Closures with a returnType and a non-block expression
  • Nodes:

    • Unsyntactic Labels, Attributes and Doc Attributes
    • Arbitrary specifier order (e.g. unsafe pub fn ...)
    • Forbidden node types (e.g. patterns in const variables, expressions in top level)
    • Missing typeAnnotations
import { rs } from "jinx-rust";

const arg_0 = rs.parseFile("fn foo(arg_0) {}").program.ast[0].parameters[0];

assert(arg_0.typeAnnotation.type === "MissingNode");

In the future, jinx-rust should eventually get a strict option.

Conversion between nodes and tokens

Attributes and Macro invocation arguments are returned as tokens in rs.parseFile.
rs exposes other methods to re-read tokens in arbitrary contexts, or to re-read nodes as tokens.

import { rs, MacroInvocation } from "jinx-rust";

const node = rs.parseFile("foo!(123);").program.ast[0].expression as MacroInvocation;

const args = rs.toCallExpressionArguments(node.tokens).ast; // ExpressionNode[]
const block = rs.toBlockBody(node.tokens).ast; // StatementNode[]

const tokens = rs.toTokens(node).ast; // TokenNode[]

Nightly features

jinx-rust supports 23 nightly features. The full list can be found in src/parser/nodes.ts under enum Feature. (link)

jinx-rust/utils

jinx-rust/utils is automatically included on install. It is a library of (mostly) auto-generated helpers from the parser's type declarations. E.g. tree traversing helpers, is_{Type}(node) functions for every type declared exported by the parser.

import { each_node, is_StatementNode } from "jinx-rust/utils";

declare const target: Node;

each_node(target, (child, parent) => {
  if (is_StatementNode(child)) {
    // gets called for every statement in target
  }
});

Gotchas

  • When a node has outer attributes, its start location expands to include them,
    its own start positions is saved under node.loc.ownStart
  • Prefer jinx-rust/utils helpers to access locations, e.g. start(node) instead of node.loc[0]
  • Exported .d.ts nodes each document their syntax, hit Go to Definition or hover over their class to see it.

    import { TraitDeclaration } from "jinx-rust";
    
    TraitDeclaration;
    // ^? import TraitDeclaration
    //    trait id<...generics>?: ...typeBounds? where ...whereBounds? { ...body }
  • filepath is not required but useful in debugging: rs.parseFile(code, { filepath })

    • Using node.loc.url() is an easy, quick way to get a clickable link to nodes causing problems.

    • To facilitate debugging in NodeJS, class Loc implements nodejs.util.inspect.custom
      Hence in console.log(node), loc is logged as node.loc.url()
      e.g. TraiDeclaration { ..., loc: "path/to/file.rs:51:18", ... }


Why jinx-rust? And why in Typescript?

  • The case for Rust Tooling to split from rustc

    Tooling and compiler should only share the spec in common. Take the tripartite system in Javascript:

    • The spec TC39 ("legislative")
    • The core V8/JC/SM ("judicial")
    • The tooling Typescript ("executive")

    Through that lens, Rust is in a rather bleek shape:

    • No spec, the 1 implementation is the law
    • The core is rustc
    • The tooling is done on top of core, sometimes even arbitrarily within core's algorithms

    Building Rust Tooling on top of rustc is a mistake akin to building Typescript's editor integration on top of v8's Turbofan.

  • The case for Core and Tooling to use different Parsers and ASTs

    Both have drastically different needs, and attempting to serve both at the same time is grossly counterproductive.

    • Core needs a minimalistic, clear and no bs parser & AST that follows the syntax allowed in the spec by the dot and to the dot. Arbitrarily injecting lints in the core parser or bloating its data structure with CST is frankly out of scope and corrupts the entire language foundation.

    • Tooling needs a parser that is much more tolerant and flexible, it should be able to overlook or bend the spec syntax rules to best infer user's intent.

  • The case for writing Rust Tooling in Typescript

    Tooling requires a language with a structure that is much more flexible, dynamic and hackable to accomodate for the wide range and open-endedness of the solutions it seeks to provide. Rust is simply not the right pick for the job, Rust is not the right pick for everything damnit.