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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@codincod/codemirror-lang-wren

v0.1.0

Published

Wren language support for the CodeMirror code editor

Readme

@codincod/codemirror-lang-wren

This package implements Wren language support for the CodeMirror code editor: a Lezer grammar, highlighting, indentation, folding and completion for the core library.

It is a fork of Josh Goebel's @exercism/codemirror-lang-wren, which is the only Lezer grammar Wren has ever had. Its precedence table and the shape of its expression rules are kept; the rest is below.

Written in part for CodinCod, a competitive coding platform, where it colours the editor people solve puzzles in.

This code is released under an MIT license.

Usage

import {EditorView, basicSetup} from "codemirror"
import {wren} from "@codincod/codemirror-lang-wren"

const view = new EditorView({
  parent: document.body,
  doc: `class Point {
  construct new(x, y) {
    _x = x
    _y = y
  }

  x { _x }
  y { _y }

  +(other) { Point.new(_x + other.x, _y + other.y) }

  toString { "(%(_x), %(_y))" }
}

var points = [Point.new(1, 2), Point.new(3, 4)]
System.print(points.reduce { |a, b| a + b })
`,
  extensions: [basicSetup, wren()]
})

What this fixes

The first reason for the fork is that upstream cannot be used: it is built for CodeMirror 0.19 and lezer 0.13, so its LanguageSupport is not the one a CodeMirror 6 editor recognises, and its parser is not one @lezer/lr can run. Nothing in the editor throws; the language simply never arrives.

The second is the parse. Measured over 1020 files (3.06 MiB) of Wren's own test suite, the Wren CLI, wren-console and DOME, upstream's grammar reads 83.82% of them with no error node, leaving 883 error nodes. This package reads 100.00%, leaving none. The 159 files in that suite meant not to compile are skipped by both.

Four of the fixes are ordinary bugs.

  • A range was two numbers. The number token ended at 1., so 1..10 lexed as 1. and .10 with an error node between them, and RangeOp never appeared in a tree. A digit is now required after the point, which is what Wren requires too.
  • A class name had to be capitalised. class foo is legal Wren and did not parse. The case of a name says nothing where only a class can stand.
  • static and construct could be members of their own. A member was allowed to be a bare name, so static origin { } read as two members, the first of them called static. Only a foreign method has no body, and it says so now.
  • A class could only inherit from a name. Wren reads an expression there and rejects a non-class when it runs, which is why its own test suite holds class Foo is null.

Three are syntax Wren has and upstream never had.

  • Attributes: #key, #key = value, #group(a, b = c) and the runtime #! form, on a class and on a method.
  • The subscript operators: [index] { } and [index]=(value) { }, and is as a method name beside the other operators.
  • A shebang, which Wren skips and every script written for the CLI opens with.

And two are the language read more closely.

  • A line break ends a statement. Wren spends no semicolons and upstream had no statement separator at all, so step and a block under it read as one call taking a block rather than as two statements, and a getter followed by anything at all ran the two together. A zero-width token now ends a statement wherever a line break did, in the way @lezer/javascript inserts a semicolon. The two places the answer runs the other way are handled too: return takes a value only from the rest of its line, and so does import "io" for Stdin. A leading dot carries a call chain on, which Wren allows and its own chained_newline.wren spends twenty lines on.
  • Fields, classes and names are told apart. _count, __count, Point and count all reach different nodes, so a theme can colour them differently. Strings are cut into their pieces rather than read a character at a time, and """raw""" takes neither escapes nor holes, which is what makes it raw.

SequenceExpression and the object patterns are gone. Both were left over from the JavaScript grammar this one started as, and Wren has no comma operator and no destructuring.

Measuring it yourself

npm run corpus -- path/to/wren/files

No corpus ships with the package, because none of that code is ours to redistribute. Point it at your own; it counts files with no error node and groups them by directory, so a project that drags the total down names itself.