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

@axis-dsl/language-service

v2.5.0

Published

Axis language services over the syntax tree: diagnostics, completions, formatting, semantic tokens, with a Monaco adapter

Readme

@axis-dsl/language-service

Everything an editor asks about an Axis file — diagnostics, completions, hover, formatting, semantic tokens, links, go to definition, references, the outline and folding — as plain functions of the source and a position, with a Monaco adapter on top.

npm install @axis-dsl/language-service

Nothing here touches an editor. Each service takes a document — the source, or a SyntaxTree already parsed from it, so a host asking several questions of one version parses it once — and a zero-based { line, character } in UTF-16 units, which is how both the Language Server Protocol and Monaco count. What comes back is editor-neutral data: ranges, markdown, edits. Two hosts adapt it: ./monaco for a browser, and @axis-dsl/language-server for anything that speaks LSP, which is what the VSCode extension runs.

The diagnostics are the compiler's own. The service does not keep a second opinion about what is wrong with a file: it runs the parser and then compileAxis, so an editor underlines exactly what a compile would report, code for code.

Usage

import { getCompletions, getDiagnostics, getHover, formatSource } from '@axis-dsl/language-service';

getDiagnostics('y = sine(x)\ncolor = 1 @ color: red');
// [{ code: 'unknown-function', severity: 'error', range, span, source: 'axis',
//    message: '`sine` is not a function - neither a built-in one nor one this file defines.' },
//  { code: 'invalid-color', …, message: "`red` is not a colour; the palette's names are capitalised: `RED`." }]

getHover('f(x) = x^2\ny = f(2)', { line: 1, character: 4 });
// { contents: '(function)\n\n```axis\nf(x) = x ^ 2\n```', range }

getCompletions('y = x @ col', { line: 0, character: 11 });
// [{ label: 'animationPeriod', kind: 'property', snippet: 'animationPeriod: ${1:8000}', … }, …]

formatSource('a=1;b=2'); // 'a = 1; b = 2'

Completions know where the cursor is — a property name after @, a value after color:, a style after use:, a keyword at the start of a statement, a name anywhere an expression goes — and offer what the manifest and the file define there, the file's own names first. A snippet is a TextMate snippet body, which VSCode and Monaco both expand natively.

Imports

A file that imports another can use what it defines, so the services that care — diagnostics, completions, hover, definitions, semantic tokens — take the compiler's resolvers as ProgramOptions:

import { createImportResolver, loadImports } from '@axis-dsl/compiler';

const files = await loadImports({ path, source }, host);
const options = { path, resolveImport: createImportResolver(files, host.resolve) };

getDiagnostics(source, options);
getDefinition(source, position, options); // [{ uri: '/work/lib/waves.axis', range }]

The services are synchronous, and reading a file is not, so the reading is done first with loadImports (and loadImages, for pictures) and handed in — the same bargain compileAxis strikes. Without a resolver every import is unresolved, as in a compile given none.

Paths

Completing a path inside import "…" or image "…" is the one question the language cannot answer alone, since what is in a directory is the host's to know. Give getCompletions a synchronous listDirectory and it answers it; a host that can only list asynchronously calls getPathContext to learn which directory the cursor is in, lists it, and hands the entries to getPathCompletions. getDocumentLinks finds every path in a document for a ctrl-click, and missingImportDiagnostic / missingImageDiagnostic build the squiggle for one the host looked for and did not find.

The path conventions themselves — withAxisExtension, importTitle, isImageUrl, imageMediaType, AXIS_IMAGE_EXTENSIONS — live in @axis-dsl/syntax and are re-exported here for a host that reaches for everything through this package.

Monaco

import { registerAxisLanguage, AXIS_LANGUAGE_ID, AXIS_DARK_THEME } from '@axis-dsl/language-service/monaco';
import * as monaco from 'monaco-editor';

registerAxisLanguage(monaco);

monaco.editor.create(container, {
    value: 'y = x^2 @ color: RED',
    language: AXIS_LANGUAGE_ID,
    theme: AXIS_DARK_THEME,
});

registerAxisLanguage is the one call an app needs. It registers the axis language on the Monaco instance you hand it — highlighting, bracket and comment behaviour, completions, hover, formatting, semantic tokens, markers, go to definition, references, highlights, the outline and folding — and defines the axis-dark and axis-light themes. It is idempotent per instance, so an app that creates several editors can call it freely, and it returns a disposable that takes every provider away again.

It takes RegisterAxisOptions, all optional: resolveImport and resolveImage with a pathOf(model) naming each model's file make imports resolve across models; semantic: false limits the markers to syntax errors; semanticHighlighting: false leaves Monaco's semantic colouring off, which is otherwise switched on because Monaco's own themes leave it off and the tokens would be computed and never drawn. The pieces are exported one by one — registerAxisCompletions, registerAxisDiagnostics and the rest — for an app that wants some of them and not others.

The app owns monaco-editor: the adapter imports only its types, and works on whatever instance it is given. Axis ships no editor component, because loading Monaco and wrapping it for a framework is app-shaped work every bundler spells differently; the docs site's playground has AxisEditor.tsx, a React wrapper to copy, and monaco.ts, the Vite loading and worker setup.

The TextMate grammar the extension highlights with ships here too, as @axis-dsl/language-service/syntaxes/axis.tmLanguage.json.

API

| Export | | | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | | getDiagnostics(doc, options?) | The parser's diagnostics and the compiler's, with ranges | | getCompletions(doc, position, options?) | What is worth offering at the cursor, paths included given listDirectory | | getHover(doc, position, options?) | Markdown for the name, keyword or property under the cursor | | formatSource / formatDocument / formatRange | The formatter, as text or as TextEdits over the document or a range | | getSemanticTokens(doc, options?) / getSemanticTokenList | Semantic tokens, LSP-encoded against SEMANTIC_TOKEN_LEGEND, or as a list | | getDefinition / getReferences / getDocumentHighlights | Where a name is defined and used, across imports for a definition | | getDocumentSymbols / getFoldingRanges | The outline and the folds | | getDocumentLinks(doc) | Every import and image path, and every URL | | getPathContext / getPathCompletions | Path completion, for a host that lists directories asynchronously | | missingImportDiagnostic / missingImageDiagnostic | The diagnostic for a path the host could not find | | compilerDiagnostics(tree, options?) / importedSymbols(tree, options?) | The compiler's view of a document: what is wrong, and what its imports define | | analyze(tree) / cursorContext(tree, offset) | The symbol table and cursor analysis the services are built on | | toTree / spanToRange / rangeToSpan / toDiagnostic | Converting between the tree's offsets and an editor's positions | | AXIS_LANGUAGE_ID, AXIS_FILE_EXTENSION, AXIS_LANGUAGE_CONFIGURATION | What an editor registers the language under, and its bracket and word rules | | KEYWORD_INFO, STATEMENT_KEYWORDS | What each keyword means, as hover and completions describe it | | ./monaco: registerAxisLanguage(monaco, options?) | Everything above, registered on a Monaco instance | | ./monaco: AXIS_DARK_THEME, AXIS_LIGHT_THEME, defineAxisThemes | The axis-dark and axis-light themes | | ./monaco: createAxisMonarchLanguage, registerAxis… | The grammar and each provider on its own |

MIT