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

@js-ox/compiler

v0.2.2

Published

JSOX compiler — JavaScript Object eXtensions, a dialect for constructing objects

Readme

@js-ox/compiler

Compile-time dialect for JSOX (JavaScript Object eXtensions): construct objects in place, then emit ordinary JavaScript.

  • <tag> { ... } constructs a value and runs the block with this bound to it
  • .prop is this.prop
  • [value] composes a part into the object being built

No runtime package. The output is plain JS.

Install

npm install -D @js-ox/compiler

Node 20+.

Vite

import { defineConfig } from "vite";
import jsox from "@js-ox/compiler/vite";

export default defineConfig({
  plugins: [jsox()],
});

Import .jsox files the same way you import .js.

CLI

npx jsox compile src/main.jsox -o dist/main.js

Writes to stdout if -o is omitted.

API

import { compile } from "@js-ox/compiler";

const { code } = compile(source);

Optional jsox.config.js in the project root can override:

  • create(tag), which returns the JavaScript expression used to create a tag
  • namespaceHandlers, an object mapping <> namespaces to factory functions or { create, finalize } handlers
  • defaultNamespace (html by default), used for tags without a namespace
  • childMethods (append, push, add by default)
  • childHelperName ($child by default; must be a valid JavaScript identifier); the compiler adds a numeric suffix if that name is already bound in the source

Scoped tags

Use <namespace:tag> to select a namespace factory. JSOX includes html and svg factories, so SVG trees can use the correct DOM namespace directly:

const icon = <svg:svg> {
  .setAttribute("viewBox", "0 0 24 24")
  <svg:circle> {
    .setAttribute("cx", "12")
    .setAttribute("cy", "12")
    .setAttribute("r", "10")
  }
}

Register project-specific factories in jsox.config.js. Each factory receives the local tag name and context, then returns a JavaScript expression string that constructs the target:

export default {
  namespaceHandlers: {
    view(tag, { namespace, explicitNamespace, qualifiedName }) {
      return `createView(${JSON.stringify(tag)})`;
    },
  },
  defaultNamespace: "view",
};

Factories that need a mutable construction phase and a different final value can use the object form. create constructs the target used as this inside the JSOX block. After that block has run, finalize receives the generated target expression and returns an expression for the selector's final value:

export default {
  namespaceHandlers: {
    react: {
      tags: ["button", "card", "Button"],
      types: {
        target: "ReactElementBuilder",
        result: "React.ReactElement",
      },
      create(tag) {
        return `new ReactElementBuilder(${tag})`;
      },
      finalize(target) {
        return `${target}.build()`;
      },
    },
  },
};
const button = <react:Button> {
  .variant = "primary"
  ["Save"]
}

Finalization is automatic, including for nested selectors: a child is finalized before it is inserted into its parent. Both callbacks run at compile time and must return JavaScript expression strings. finalize also receives a second context argument containing tag, namespace, explicitNamespace, and qualifiedName.

The object form can also expose editor metadata. tags is an array of names offered by the LSP after the namespace prefix. types.target specifies the TypeScript type of this during construction, and types.result specifies the type returned after finalization. A type hint may be a string or a (tag, context) => string function. These fields do not affect emitted code.

With that configuration, <card> and <view:card> both use the view factory. <html:button> and <svg:circle> can still select the built-in factories explicitly.

The existing create(tag) option remains supported and configures the built-in html handler for backward compatibility.

The language server loads the same configuration and uses a namespace factory's returned expressions for TypeScript inference. With a finalizer, the creation expression types this inside the block while the finalization expression types the selector result. Adding namespaces does not change unqualified HTML typing unless defaultNamespace is explicitly set to another namespace.