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

@ng-org/shex-orm

v0.1.2-alpha.10

Published

CLI tool to convert SHEX shapes to schemas and TypeScript definitions ("shape types") that can be used for creating RDF ORM objects.

Readme

Schema Converter SHEX > TypeScript

CLI tool to convert SHEX shapes to schemas and TypeScript definitions ("shape types") that can be used for creating RDF ORM objects.

You need this utility for compiling schemas for use with the TypeScript RDF ORM.

Reference documentation

Reference documentation is available here on docs.nextgraph.org.

About RDF

RDF (Resource Description Framework) is a standard to describe data. Rather than organizing data as tables (e.g. SQL) or trees (e.g. JSON), RDF represents data as a non-hierarchical, unstructured set of triples (a graph aka network).

Each triple consists of a subject (about which you are describing something), a predicate (the property of the relationship, e.g. the first name), and an object (the value of that property or a reference). Triples belong to documents, also called graphs in the context of RDF. Subjects, predicates and graphs are all IRIs (the generalization of URLs). There are many specifications for describing data, to aid application interoperability.

RDF's flexible and schema-less design aids in schema-evolution, interoperability, and data relationships. You are advised to take a moment to get yourself familiar with RDF if you are new to it.

To work with RDF in applications and bring structure to it, you need to define schemas.

Schemas define what data you want to query, validate, and see materialized in a TypeScript object.

Setup

Install @ng-org/shex-orm as dev dependency.

npm install --save-dev @ng-org/shex-orm

Then run

npx rdf-orm build --input ./src/shapes/shex --output ./src/shapes/orm

In your app's package.json, you are advised to add something like the following:

{
    "scripts": {
        "build:orm": "rdf-orm build --input ./src/shapes/shex --output ./src/shapes/orm",
        "dev": "npm run build:orm && vite dev",
        "build": "npm run build:orm && vite build"
    }
}

Writing SHEX Schemas

Below, you can see an example SHEX schema as an orientation. You can also check out the SHEX schema of an example app.

PREFIX ex: <did:ng:z:>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

ex:ExpenseShape {
  # `a` is a shorthand for the standard RDF type predicate `rdfs:type` or in the long form: `http://www.w3.org/1999/02/22-rdf-syntax-ns#type`
  a [ex:Person]                    # Required type <did:ng:z:Person>
      // rdfs:comment "This is a comment that will appear in the generated TypeScript type" ;
  ex:name xsd:string ;             # Required string
  ex:email xsd:string * ;          # Zero or more strings (set)
  ex:height xsd:float ;            # Required number
  ex:age xsd:integer ;             # Required integer. NOTE: TS does not support integers and you are recommended to use xsd:float unless you know what you are doing.
  ex:friends IRI * ;               # Set of IRIs
  ex:isRecurring xsd:boolean ;     # A boolean value
  ex:address @ex:AddressShape ;    # A nested object shape.
  ex:paymentStatus [ex:Paid ex:Pending ex:Overdue] ; # Enum
}

# `EXTRA a` means that the property `a` may have other values in addition to `ex.Address`
# `CLOSED` means that no other predicates may be present for a given address. Be careful, see performance notes below.
ex:AddressShape CLOSED EXTRA a {
  a [ ex:Address ] ;
  ex:name xsd:string ;
}

See what output was generated below.

SHEX Quick Reference

| Syntax | Meaning | TypeScript Type | | ---------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | value xsd:string | Required, exactly one | string | | value xsd:boolean ? | Optional, zero or one | boolean \| undefined | | value xsd:float * | Zero or more | Set<number> | | value xsd:string + | One or more | Set<string> (non-empty) | | value IRI | Reference to another object | string (IRI) | | value xsd:string OR xsd:float | multiple types allowed | string \| number | | value @ex:PersonShape | nested object | Person | | value @ex:AudioAsset OR @ex:VideoAsset | multiple nested object types allowed | AudioAsset \| VideoAsset | | shape attribute EXTRA <predicate name> | for literal types: multiple values allowed | e.g. Set<string \| "some literal"> instead of "some literal" | | shape attribute EXTRA <predicate name> | for object types: invalid child objects will be ignored instead of the parent becoming invalid | | | shape attribute CLOSED | Additional quads (not matching any predicate) make an object become invalid | |

You will then pass the shape type of a shape definition to the ng sdk:

Note: If you specify more than one allowed nested shape and the data matches both shapes, the first shape will "win". In general though, you are advised to define shapes so that this does not happen. Specify different types for each shape instead (e.g. a [ex:DistinguishingTypeOnlyAvailableInThisData] ;).

Generated Output

For each SHEX file, the tool creates three TypeScript files:

  • A schema file like person.schema.ts
  • A typings file like person.typings.ts
  • A shape type file like person.shapeTypes.ts which contains a ShapeType that consists of the schema, the type, and the IRI of the main shape. This is what you pass to the ORM.

The transformers for converting SHEX to schema and typings files are based on @ldo/traverser-shexj.

Representation in TypeScript

Every type has the following two readonly properties:

  • @id the subject IRI
  • @graph the graph (document) NURI

In addition to that you will usually find the @type property: The RDF type IRI (from rdfs:type) is always converted to the property name @type by default. You are strongly encouraged to specify a type in your schema.

Property names are derived of the last part of the predicate IRI. In case of name collisions the 2nd, 3rd, etc. last part is used added as well.

Predicates with a cardinality higher than 1 (i.e., maxCardinality > 1 or maxCardinality === -1 for unlimited) are represented as TypeScript Set<T> types. Note that SHEX allows you to specify cardinalities not representable in TypeScript, for example greater than 2 and less than 4. When you modify an object so that it does not fulfil those requirements anymore, it will disappear since it doesn't match the shape anymore.

Currently all RDF types are mapped to string, number, or boolean, including date which is mapped to an ISO 8601 date string.

Use in the ORM

In the ORM, you pass the generated ShapeType to the respective functions (getObjects(), insertObject(), useShape(), OrmSubscription.getOrCreate()), for example:

import { useShape } from "@ng-org/orm/react";
import { TestObjectShapeType } from "../shapes/orm/testShape.shapeTypes";

export function TestComponent() {
    const {data: testObjects} = useShape(TestObjectShapeType, {graphs: ["did:ng:i"]});
    ...
}

Nested Object Validity

Note that when a nested object is invalid, the whole parent object is invalid too (i.e. it won't be loaded). If you want to allow for invalid children (that are then not materialized in TypeScript), you can mark the property as EXTRA, e.g.:

ex:ExpenseShape EXTRA ex:address {
  ex:address @ex:AddressShape ;
}

Performant Queries and Writing Efficient Schemas

In the background, the ORM converts shape types and the scope of a request into SPARQL queries. For performant queries, there are few things you can keep in mind:

  • Pass a graph and potentially subject scope when creating an ORM subscription: If you know in which graph or which subjects your data is, this narrow the query a lot.
  • Use mandatory predicates (e.g. rdfs:name xsd:string ;): When you specify a mandatory predicate, the SPARQL engine will ignore all objects without it.
  • Specify types or other mandatory predicates (e.g. a [ ex:HomeAddress ] ;). This will narrow the search space even more. Especially if your literals are rare.
  • Use CLOSED shapes only if you have a narrow graph or subject scope: To track excess quads for objects with closed shapes, the SPARQL query will fetch all quads within the graph and subject scope. If you don't scope your request, this might cause a query to return all data in your store. Child objects with a closed shape are less affected because their SPARQL queries are always scoped (to the subject they are referenced with). Don't use closed shapes unless you are careful and have a good reason.

NextGraph

NextGraph brings about the convergence of P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs.

This open source ecosystem provides solutions for end-users (a platform) and software developers (a framework), wishing to use or create decentralized apps featuring: live collaboration on rich-text documents, peer to peer communication with end-to-end encryption, offline-first, local-first, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing semantic data (RDF), rich text, and structured data formats like JSON, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of CRDTs. Documents can be linked together, signed, shared securely, queried using the SPARQL language and organized into sites and containers.

More info here https://nextgraph.org

Support

Documentation can be found here https://docs.nextgraph.org

And our community forum where you can ask questions is here https://forum.nextgraph.org

License

3 files have been taken from LDO project and modified by us. 1 file has been taken from LDO project without modifications.

All from repository https://github.com/o-development/ldo/tree/main/packages/schema-converter-shex at commit c461beb5a5acf379d3069f0734dfa5d57fd20eaa (Aug 23, 2025) licensed under MIT License with copyright attribution to : Copyright (c) 2023 Jackson Morgan. Those 4 files are here relicensed under Apache 2.0 and MIT.

All subsequent commits on those files, and any other file in this package are licensed under either of

  • Apache License, Version 2.0 (LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0)
  • MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT) at your option.

SPDX-License-Identifier: Apache-2.0 OR MIT

Contributions license

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as below, without any additional terms or conditions.


NextGraph received funding through the NGI Assure Fund and the NGI Zero Commons Fund, both funds established by NLnet Foundation with financial support from the European Commission's Next Generation Internet programme, under the aegis of DG Communications Networks, Content and Technology under grant agreements No 957073 and No 101092990, respectively.