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

sparqlc

v0.3.0

Published

Typed SPARQL query modules for Node.js and build tools. Write queries in `.rq` (query) and `.ru` (update) files, import them as ESM, and execute against a SPARQL endpoint or in‑memory dataset with strong TypeScript types.

Readme

sparqlc

Typed SPARQL query modules for Node.js and build tools. Write queries in .rq (query) and .ru (update) files, import them as ESM, and execute against a SPARQL endpoint or in‑memory dataset with strong TypeScript types.

Install

npm i sparqlc

To use .rq/.ru files directly at runtime in Node.js, install the companion loader:

npm i -D node-loader-sparql

Then run Node with the loader enabled (Node 20.6+/22+ ESM --import):

node --import node-loader-sparql your-script.mjs

Or set once for your environment:

export NODE_OPTIONS="--import node-loader-sparql"

In Mocha (or similar test runners) you can also add node-loader-sparql to the require list, as done in this repo’s tests.

Usage

Select queries export an executable function. The return type depends on the client you pass (sparql-http-client):

  • StreamClient → async generator of bindings
  • ParsingClient → array of bindings (parsed terms)

Construct/Describe queries return an RDF/JS DatasetCore with a ParsingClient, or a Stream with a StreamClient.

// fruits/select-relative-uris.rq
// SELECT ?label WHERE { <fruits/Banana> rdfs:label ?label }

import env from '@zazuko/env'
import { ParsingClient } from 'sparql-http-client'

const { default: selectBanana } = await import('./fruits/select-relative-uris.rq', {
  with: { base: 'http://example.org/' },
})

const client: ParsingClient = /* ... */

const rows = await selectBanana({ env, client })
// → [{ label: env.literal('Banana') }, ...]

If you omit client from options, the function returns the final serialized SPARQL string instead of executing an HTTP request:

const sparqlQueryString = await selectBanana({ env })

Updates (.ru) export an executable function returning void when used with a ParsingClient:

const { default: insertData } = await import('./queries/insert-data.ru')

await insertData({ env, client })

Binding parameters with sparqlc:param

Queries can declare variables and placeholders to be bound at execution time using the sparqlc:param SPARQL function.

Declaring parameters in SPARQL queries

Declare the sparqlc: prefix:

PREFIX sparqlc: <https://sparqlc.described.at/>

You can use sparqlc:param(...) in BIND(...) expressions, FILTER(...) expressions, or anywhere SPARQL expressions are valid:

  • String literal parameter keys: Identify parameters by string name.

    # queries/select-by-type.rq
    PREFIX sparqlc: <https://sparqlc.described.at/>
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    
    SELECT ?res ?label WHERE {
      BIND(sparqlc:param("type") AS ?type)
    
      ?res a ?type ;
           rdfs:label ?label .
    }
  • NamedNode / IRI parameter keys: Identify parameters using full IRIs or prefixed names (such as schema.org terms).

    # queries/construct-named-node-param.rq
    PREFIX sparqlc: <https://sparqlc.described.at/>
    PREFIX schema: <http://schema.org/>
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    
    CONSTRUCT {
      ?fruit rdfs:label ?label .
    } WHERE {
      BIND(IRI(sparqlc:param(schema:mainEntity)) AS ?fruit)
    
      ?fruit rdfs:label ?label .
    }
  • In FILTER expressions:

    PREFIX sparqlc: <https://sparqlc.described.at/>
    
    SELECT ?s ?val WHERE {
      ?s ?p ?val .
      FILTER(?val = sparqlc:param("expected"))
    }
  • Scoped evaluation: sparqlc:param can be used inside GRAPH, OPTIONAL, SERVICE, MINUS, unions, sub-selects, and update operations (INSERT, DELETE). Parameter values are injected into the query via appropriately scoped VALUES clauses according to SPARQL bottom-up evaluation semantics.

Passing parameters at execution time

Pass parameter values as the first argument(s) to the imported query function. sparqlc supports several formats:

  • Plain object dictionary (Record<string, Term>):

    import env from '@zazuko/env'
    const { default: selectByType } = await import('./queries/select-by-type.rq')
    
    const rows = await selectByType(
      { type: env.namedNode('http://example.org/Fruit') },
      { env, client }
    )
  • RDF/JS TermMap / Map<Term, Term | Term[]>: Useful for NamedNode parameter keys and full control over RDF terms.

    import env from '@zazuko/env'
    const { default: construct } = await import('./queries/construct-named-node-param.rq')
    
    const params = env.termMap([
      [env.ns.schema.mainEntity, env.namedNode('http://example.org/fruits/Banana')],
    ])
    
    const dataset = await construct(params, { env, client })
  • URLSearchParams: Useful for query strings.

    const params = new URLSearchParams([['type', 'http://example.org/Fruit']])
    const rows = await selectByType(params, { env, client })
  • Multiple parameter sources: Multiple parameter maps or objects can be provided in sequence before the options argument.

    const rows = await selectQuery(params1, params2, { env, client })

Runtime query options

Queries can be modified at execution time using runtime options:

  • distinct: boolean — dynamically add or remove the DISTINCT modifier
  • from / fromNamed: NamedNode | string | (NamedNode | string)[] — specify default (FROM) or named (FROM NAMED) graph IRIs
  • limit: number — specify or override LIMIT
  • offset: number — specify or override OFFSET
  • orderBy: variable, direction tuple [variable, 'ASC' | 'DESC'], or array thereof — sort results with compile-time type checking restricted to variables present in the query
  • processors: optional array of @hydrofoil/sparql-processor instances to transform the parsed query before serialization
const rows = await selectFruit({
  env,
  client,
  distinct: true,
  limit: 10,
  offset: 20,
  orderBy: [
    ['label', 'DESC'],
    'fruit',
  ],
  from: 'http://example.org/fruits',
  fromNamed: [
    'http://example.org/graphs/fruits-1',
    env.namedNode('http://example.org/graphs/fruits-2'),
  ],
})

Programmatic API (compile)

sparqlc provides a compile function to compile SPARQL query strings directly in JavaScript or TypeScript:

import { compile } from 'sparqlc'
import env from '@zazuko/env'
import { ParsingClient } from 'sparql-http-client'

const source = `
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name WHERE { ?s foaf:name ?name }
LIMIT 10
`

const { execute, returnType } = compile(source)
console.log(returnType) // e.g. 'Select'

const client: ParsingClient = /* ... */
const rows = await execute({ env, client })
// Or omit `client` to get the final generated SPARQL query string:
const sparqlString = await execute({ env })

Base IRI via import attributes

You can pass a base IRI for resolving relative IRIs in the query using ESM import attributes:

const { default: q } = await import('./queries/select-relative-uris.rq', {
  with: { base: 'http://example.org/fruits/' },
})

This mirrors the behavior covered by the test suite and is supported by the node-loader-sparql package.

Separate module instances per attribute set

When using the node-loader-sparql runtime loader, each distinct set of import attributes (e.g., a different base) resolves to a distinct module URL. That means imports with different with values produce separate module instances and cache entries:

const a = await import('./q.rq', { with: { base: 'http://ex.org/a/' } })
const b = await import('./q.rq', { with: { base: 'http://ex.org/b/' } })

// a.default and b.default are separate compiled modules configured with different base IRIs

This is implemented in the loader’s resolve hook by incorporating the attributes into the resolved URL, ensuring Node’s module map keys them separately.

Type hints

sparqlc ships TypeScript declarations for the executors:

  • ExecuteSelect<TBindings>
  • ExecuteConstruct
  • ExecuteAsk
  • ExecuteUpdate

See packages/sparqlc/test/index.test.ts for end‑to‑end examples that match the types above.