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

obix-compiler-dop

v0.5.0

Published

The DOP lowering of the .obix compiler: the Vue frontend artifacts (canonical SFC, script setup, template) lowered into the canonical, frontend-neutral OBIX DOP IR of obix-compiler-ir — with the source provenance kept in a separate document and the origin

Readme

obix-compiler-dop

Previous name: @obinexusltd/obix-compiler-dop — OBIX packages are named without an npm scope since decision D-102 (2026-09-29); the package, its version and its exports are unchanged.

The DOP lowering of the .obix compiler — the Vue frontend's artifacts (canonical SFC, <script setup>, template) lowered into the canonical, framework-neutral OBIX DOP IR of obix-compiler-ir.

npm install obix-compiler-dop
   Vue frontend                                                      Vue frontend ───┐
     SFC · script setup · template ──► lowerVueToDop ──► IR                          ├──► canonical OBIX DOP IR ──► later: native / hybrid
     (frontend artifacts)              (this package)   (obix-compiler-ir)    React frontend ┘   (React: a later phase, lowering independently)

The IR is the semantic authority of OBIX (D-44); this package is one of its writers. It reads what the Vue frontend produced — the template's sourceAst, which is what the author wrote before Vue's transforms, and the Babel AST of the script setup — and writes an IR that is plain, frozen, valid and free of Vue: no Vue AST node, no directive name (v-if, v-for, v-model, v-slot), no React or JSX node, no runtime object. Where the source said each thing is a separate provenance document. The frontend's own artifacts are kept beside the result, never inside it.

import { lowerVueToDop } from "obix-compiler-dop";

// the stages of the family run first; the lowering is given what they returned
const result = lowerVueToDop({ sfc, script, template });   // script: the result of the stage that owns the file's script

result.status;                      // "compiled" | "deferred" | "failed" | "absent"
result.artifact.ir;                 // the canonical IR — serializeIr(ir), irEqual(a, b) from obix-compiler-ir
result.artifact.provenance;         // node id → range in the file; the frontend's name and version; every import as written
result.artifact.frontend;           // { sfc, script, template } — the frontend's own artifacts, untouched

The result is the family's stage result (obix-compiler-diagnostics), and like every stage the lowering is total — it throws only for an input that is not the stages' output (a TypeError, a programming error) — and speaks only for itself:

| status | when | |---|---| | compiled | the IR, its provenance and the frontend artifacts; no diagnostics | | deferred | the source uses a construct that is valid for the frontend and not lowered yet: one diagnostic per construct (OBIX_DOP_DEFERRED_*), with its place — and no IR at all, never a partial one, because an IR that is missing a piece means something else | | failed | an earlier stage's verdict leaves nothing to lower (OBIX_DOP_UPSTREAM_FAILED: the SFC parse or a stage reported errors), or the lowering built something the IR checker refuses (OBIX_DOP_INVALID_IR, a defect of the lowering — never returned as IR) | | absent | the file has no template and no script: nothing to lower |

A stage that defers the file makes the lowering defer it (OBIX_DOP_UPSTREAM_DEFERRED). What is built is checked with checkIr before it is returned, and leaves as parseIr(serializeIr(ir)) — the canonical document, deep-frozen, sharing no object with the frontend's.

What each thing becomes

| The Vue frontend read | The IR has | Notes | |---|---|---| | defineProps({...}), defineProps<T>(), withDefaults(...), a type literal / interface / alias of the same file | props | type in the IR's own words (string number boolean array object function unknown); required; a constant default (a value, or a function that returns one, as Vue calls it). Boolean props mean what HTML boolean attributes mean | | const x = ref(<constant>) | state | changes only by an assign step | | const y = computed(...), and a constant const | derived | a pure expression over props, state, derived values | | a function / arrow of the setup | action | count.value++, n.value += 2, a.value = b.value + 1, other() → assign / invoke steps, in order | | watch(source, (now, before) => {...}) | effect | watches a ref or a getter that reads the same twice; runs after a change, before its component renders, with the new and the previous value — effects that touch nothing of each other's (below) | | :title="x" | a property binding | title — with its expression | | title="x" | an attribute | fixed | | role, tabindex, alt, for, aria-* (fixed or bound) | accessibility of the element | kept apart from the other attributes, given exactly as written — nothing is inferred | | @click="…", v-on:click, a method name, a function, several statements | an event binding | event: "click" and steps; $event (or the function's parameter) is the event payload | | {{ expr }} and text | text with static and display parts | adjacent text and interpolations run together | | v-if / v-else-if / v-else, and <template v-if> | a conditional | branches with conditions; otherwise; a <template> wrapper is transparent | | v-for="(item, i) in items", :key | an iteration | source, item, index, key, body; over arrays | | <Child :a="x" b="y">…</Child> | an invocation + a dependency | the dependency is addressed by module specifier and export, exactly as imported — never resolved here | | default slot content, <template #name="{ item }"> | projection contents | the default content is the slot named default; parameters bind arguments | | <slot name="x" :arg="…">fallback</slot> | a projection | with arguments and a fallback | | <style lang scoped> | styles metadata | language, scope (component | global), the text — nothing is compiled |

Expressions are lowered by one function for the script and the template: literals, arrays, objects, references (prop state derived local), member and index access, ! - +, + - * / %, === !== < <= > >=, && || ??, and the choice a ? b : c. TypeScript's own syntax (as, !, satisfies, type arguments) is erased: it has no meaning at run time.

Not in the IR, on purpose

  • Vue's names. v-if, v-for, v-model, v-slot, v-bind, v-on, ref, computed, defineProps, <slot> — the frontend keeps them. tests/vuets/dop-equivalence.test.mjs scans every IR the corpus lowers for a word of Vue's and for anything that is not plain data.
  • Vue's objects. No RootNode, ElementNode, DirectiveNode, SimpleExpressionNode, no Babel node, no .value of a ref.
  • Locations. Ranges are in the provenance document, keyed by id: component, props.<name>, state.<name>, view.<i>.children.<j>.events.<k>… (the id scheme is specified in test/support.mjs, independently of the lowering).
  • Frontend artifacts. They travel in artifact.frontend, next to the IR, for diagnostics and provenance.

Deferred — with a diagnostic each, never a guess

Vue constructs the kernel of the IR does not model yet: v-model, v-show, v-html, v-text, v-once, v-memo, v-cloak, custom directives, object v-bind / v-on (v-pre lowers: Vue's parser leaves raw text and plain attributes); dynamic class / style, dynamic names, modifiers, key / ref outside their place; built-in components (Transition, KeepAlive, Teleport, Suspense, component), dynamic and recursive components, events on components, class / style on a component (Vue merges them into the invoked root); calls, function values, optional chaining, undefined, spread, and an empty {{ }} in expressions (-0 lowers: it is the negation of 0); if, loops, return, declarations, await in actions; watchEffect, lifecycle hooks, watch options; reactive, provide / inject, defineEmits, defineExpose, defineModel…; a normal <script>; lang="tsx" / "jsx"; <style module>, v-bind() in CSS, <style src>.

Deferred because the IR would mean something else than Vue does — found by running generated programs on both, each with its place:

  • a name the IR cannot carry — café, größe, a kebab-case prop such as "a-b" (isIrIdentifier: ASCII letters, digits, _ and $, not a leading digit);
  • a name that is two things — a prop and a state, a derived value or an action of the same name (the IR keeps them in one namespace) — and derived values that read one another in a circle;
  • a name whose declaration nothing says — a const whose initializer reads the name it declares, or consts that read each other, however far round: each name on the circle is a deferral at its declaration, with the way round (checkWaiting). A const that reads a name whose deferral is said elsewhere says nothing more; when the names wait on each other nothing would, and the name used to be left out without a word;
  • effects that Vue orders and the IR does not (src/effects.ts): Vue runs effects in the order their values changed, the IR in the order they are declared, so an effect that changes what another watches, reads or changes is deferred, and so is one that changes what it watches; and Vue compares a derived value by the identity of a cached result, so an effect that watches a new array or a new object at every read — a literal, a derived value made of one, a prop that is not a string, a number or a boolean — is deferred.

Also deferred, by decision, in this phase: the "obix" authoring alias — import { ref } from "obix" is recorded in the provenance as written and is not resolved (a later phase resolves it, never by string replacement; obix is an alias, never a package) — a filesystem host (a defineProps<T> whose T lives in another file is stopped by the script stage, before this one), JSX / TSX, source-map composition, runtime reactivity, emit, and the React, native and hybrid stages.

Dependency role

obix-compiler-diagnostics (the stage-result contract), obix-compiler-ir (the target), the frontend stages whose artifacts it reads (-sfc, -script, -template) and @vue/compiler-core — for the numeric NodeTypes / ElementTypes by which it reads the template's sourceAst; it imports no Vue runtime and no other Vue-family package (obix-vue.json lists it, with the reason). The IR it produces reaches none of them. Graph rule R5 keeps the compiler family out of every browser graph.

Tests

npm test -w obix-compiler-dop — 196 tests: 95 written before the code (view · script · events · structure · components · effects · statuses); 70 that mutation testing asked for (exact · exact-template — the refusal of a wrong input with its reason, names, the order of the diagnostics, TypeScript syntax erased everywhere, what cannot be written or invoked and why, what the analysis of effects is given when a step could not be made, a slot header that cannot be lowered, and what the lowering does with a tree the parser never makes); 31 that generated sources and programs asked for (effect-order · collisions — the effect analysis, name collisions, derived circles, the names that nothing said and the names a destructuring binds, each with its exact message and place; generated — the eight laws over generated sources, with a meta-test that a lowering that breaks each law is caught): the IR expected is written by hand from the schema, and the id scheme and provenance are specified independently of the lowering.

The equivalence proof is one level up, because it needs the real Vue runtime: tests/vuets/dop-equivalence.test.mjs runs each fixture of tests/corpus/dop (every component a byte-identical .vue / .obix pair) on Vue's own runtime — official compiler, createRenderer — and on the reference evaluator of the IR the lowering produced, in both syntaxes, and compares the normalized trees at every step; tests/vuets/dop-differential.test.mjs does the same for generated programs. Both generators are seeded, so a failure is reproduced from its seed: OBIX_GENERATED=<first>:<count> node --test test/generated.test.mjs (here) and OBIX_DIFFERENTIAL=<first>:<count> node --test tests/vuets/dop-differential.test.mjs (from the repository root).

Installation

npm install obix-compiler-dop

API surface

  • obix-compiler-dop — 2 value exports: OBIX_DOP_CODES, lowerVueToDop
  • Type declarations: ./dist/index.d.ts (and a declaration next to every JS entry point).

Architecture role

obix-compiler-dop is part of the OBIX compiler (build-time tooling): it never runs in an application's browser graph.

The architecture of OBIX — the package families and which packages are public API — is indexed in the umbrella: docs/architecture.md.

Package relationships

Testing

  • 17 test files ship in the npm package (test/): the evidence of the package's contract, published so that its verification can be inspected — not runtime code (no entry point reaches them).
  • Standalone: 1 of 17 — it reads nothing outside the package.
  • Need the OBIX development / test harness: 16 — they read the OBIX monorepo's shared harness, oracles or fixtures, so they do not run from an npm install or from this package's repository alone; they are shipped for inspection and provenance:
    • test/call.test.mjs — imports test/support.mjs, which is not shipped
    • test/collisions.test.mjs — imports test/support.mjs, which is not shipped
    • test/components.test.mjs — imports test/support.mjs, which is not shipped
    • test/effect-order.test.mjs — imports test/support.mjs, which is not shipped
    • test/effects.test.mjs — imports test/support.mjs, which is not shipped
    • test/events.test.mjs — imports test/support.mjs, which is not shipped
    • test/exact-template.test.mjs — reads ../../../tests/vuets/compose.mjs, outside the package
    • test/exact.test.mjs — reads ../../../tests/vuets/compose.mjs, outside the package
    • test/generated.test.mjs — imports test/laws.mjs, which is not shipped
    • test/laws.mjs — reads ../../../tests/vuets/compose.mjs, outside the package
    • test/outputs.test.mjs — imports test/support.mjs, which is not shipped
    • test/script.test.mjs — reads ../../../tests/vuets/compose.mjs, outside the package
    • test/statuses.test.mjs — reads ../../../tests/vuets/compose.mjs, outside the package
    • test/structure.test.mjs — imports test/support.mjs, which is not shipped
    • test/support.mjs — reads ../../../tests/vuets/compose.mjs, outside the package
    • test/view.test.mjs — imports test/support.mjs, which is not shipped
  • Run them with npm test (node --test "test/*.test.mjs") in the OBIX monorepo, which provides the test tooling (Node's test runner, TypeScript) and the harness.

Documentation

Repository

  • https://github.com/obinexus/obix-compiler-dop — [email protected]:obinexus/obix-compiler-dop.git
  • Issues: https://github.com/obinexus/obix-compiler-dop/issues
  • The repository is a clean export of the package from the OBIX monorepo. Its lineage — the sources it was recovered from and its earlier names — is PROVENANCE.json, shipped in this package; the repository's copy also records the monorepo commit it was exported from.

License

MIT — see LICENSE.