Packaging the Loom language
The @athrio/loom-lang package is the language behind every .loom file — the Volar extended language and the engine that tangles it. The command-line tool and the VS Code extension both build on it: they import its source and bundle it into their own output, so this package exposes TypeScript source rather than a precompiled library.
The manifest
Two field groups carry the package's shape. The imports field defines one package subpath alias, #ast/*, for the AST source, so internal imports stay stable rather than relative. The exports field names the public entry points — ./LoomCompiler, ./LoomTangler, ./LoomFormatter, ./PackageConfig, and ./LoomServer — each pointing at a source file the consumer inlines. ./weave/WovenCorpus exposes the woven-corpus schema on its own, so the reader site types its rendered pages against the same definition the weave pass produces rather than a hand-kept copy, ./weave/LoomWeaver exposes the writer the CLI drives to emit that data, and ./weave/LoomContents the writer it drives to regenerate the book's own table of contents. ./ast/LineRanges and ./ast/WeftClassifier expose the first two stages of reading a loom, so the tree-sitter grammar's test checks every line's kind against the classifier the grammar ports. @athrio/loom-ast supplies the shared domain types the verbs build and the toolchain reads, a workspace dependency.
The main and bin fields point at built output: dist/loom-server.js is the bundled language server, and the loom-language-server binary launches it. The runtime libraries the server needs — Volar, Effect, the volar-service-* plugins, and ignore, which matches the patterns that leave a loom out of a project — are dependencies. @athrio/loom-service-typescript is a devDependency: the server loads it at runtime from the Loom store rather than bundling it, so it is present only to build and test against. @effect/platform-bun is a devDependency used only by the tangler's end-to-end test, which provides it as the real filesystem the tangler writes through. vscode-uri is a type-only devDependency.
{{ version = ${version} }} {{ effect = ${effect} }}
{
"name": "@athrio/loom-lang",
"version": "::[version]",
"license": "MIT",
"main": "./dist/loom-server.js",
"bin": {
"loom-language-server": "./bin/loom-language-server.js"
},
"imports": {
"#ast/*": "./src/ast/*.ts"
},
"exports": {
"./LoomCompiler": "./src/LoomCompiler.ts",
"./LoomTangler": "./src/LoomTangler.ts",
"./LoomFormatter": "./src/LoomFormatter.ts",
"./PackageConfig": "./src/PackageConfig.ts",
"./LoomServer": "./src/LoomServer.ts",
"./weave/WovenCorpus": "./src/weave/WovenCorpus.ts",
"./weave/LoomWeaver": "./src/weave/LoomWeaver.ts",
"./weave/LoomContents": "./src/weave/LoomContents.ts",
"./ast/LineRanges": "./src/ast/LineRanges.ts",
"./ast/WeftClassifier": "./src/ast/WeftClassifier.ts"
},
"scripts": {
"build": "vite build",
"watch": "vite build --watch"
},
"dependencies": {
"@athrio/loom-config": "workspace:*",
"@athrio/loom-ast": "workspace:*",
"@athrio/loom-lang-services": "workspace:*",
"@volar/language-core": "^2.4.28",
"@volar/language-server": "^2.4.28",
"@volar/language-service": "^2.4.28",
"effect": "::[effect]",
"ignore": "^7.0.5",
"volar-service-css": "^0.0.71",
"volar-service-html": "^0.0.71",
"volar-service-markdown": "^0.0.71",
"vscode-html-languageservice": "^5.6.2"
},
"devDependencies": {
"@athrio/loom-service-typescript": "workspace:*",
"@effect/platform-bun": "::[effect]",
"vscode-uri": "^3.1.0"
}
}The launcher
An editor starts the language server by spawning the loom-language-server binary. The binary is a thin launcher over the bundle, made runnable on its own by a shebang line.
It answers --version from the package manifest, printing the version an editor reads to learn which server it runs. For every other invocation it loads the bundled server at dist/loom-server.js, which begins serving the moment it loads.
#!/usr/bin/env node
if (process.argv.includes('--version')) {
const pkgJSON = require('../package.json')
console.log(pkgJSON.version)
} else {
require('../dist/loom-server.js')
}The TypeScript config
The tsconfig.json extends the workspace-root tsconfig.base.json and covers both the src and test directories. Vite produces the dist bundle, so the configuration is a development tool only.
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "out"
},
"include": ["src", "test"]
}