This guide explains how to build and use RIDDL JavaScript modules as local npm packages (without publishing to npmjs.com).
- ✅ NEW: Full TypeScript support - All Scala types converted to plain JavaScript objects
- Scala
List→ JavaScriptArray - Scala case classes → Plain JS objects with properties
- All values are JSON-serializable
- Scala
- ✅ NEW: Error arrays instead of strings - Errors returned as structured array of objects
- ✅ JavaScript-friendly return types - All methods return
{ succeeded: boolean, value?: object, errors?: Array<object> } - ✅ Added RiddlAPI facade with stable, non-minified method names
- ✅ Fixed minification issue - all API methods preserve their names in production builds
- ✅ Complete TypeScript type definitions and examples
- ✅ Current version:
1.0.1-8-90a737de-20260108-0749 - ✅ Package size: ~244KB (production build)
📘 See TYPESCRIPT_API.md for complete TypeScript documentation and examples.
Build all JavaScript modules:
./scripts/pack-npm-modules.shOr build specific modules:
./scripts/pack-npm-modules.sh riddlLib utilsAvailable modules:
riddlLib- Main RIDDL libraryutils- Utilitiespasses- Validation passesdiagrams- Diagram generationlanguage- Core language parser
cd /path/to/your/project
npm install /Users/reid/Code/ossuminc/riddl/npm-packages/ossuminc-riddl-lib-*.tgzimport { RiddlAPI } from '@ossuminc/riddl-lib';
// Parse RIDDL source
const result = RiddlAPI.parseString("domain MyDomain is { ??? }");
if (result.succeeded) {
console.log("Parse successful!");
console.log("Domains:", result.value.domains);
// result.value is a plain JS object with domains array
} else {
console.error("Parse errors:");
result.errors.forEach(err => {
console.error(` [${err.kind}] ${err.message} at line ${err.location.line}`);
});
// result.errors is an array of error objects
}
// Parse for syntax highlighting
const tokens = RiddlAPI.parseToTokens("domain Example is { ??? }");
if (tokens.succeeded) {
tokens.value.forEach(token => {
console.log(`${token.kind} at line ${token.location.line}`);
});
// tokens.value is a JavaScript Array of token objects
}
// Get version
console.log("RIDDL version:", RiddlAPI.version);The @ossuminc/riddl-lib package includes a RiddlAPI facade object with stable, non-minified method names (preserved even in production builds). This solves the issue where Scala.js minification made method names unusable from JavaScript.
All methods return JavaScript-friendly result objects with a succeeded boolean field instead of Scala's Either type.
interface ParseResult<T> {
succeeded: boolean;
value?: T; // Present when succeeded is true
errors?: string; // Present when succeeded is false
}All methods are exported with stable names:
-
parseString(source, origin?, verbose?)- Parse a RIDDL source string
- Parameters:
source: string- The RIDDL source codeorigin: string- Optional origin identifier (default: "string")verbose: boolean- Enable verbose error messages (default: false)
- Returns:
{ succeeded: boolean, value?: Root, errors?: string }
-
parseStringWithContext(source, origin, verbose, context)- Parse with a custom platform context
- Parameters:
source: string- The RIDDL source codeorigin: string- Origin identifierverbose: boolean- Enable verbose error messagescontext: PlatformContext- Custom platform context
- Returns:
{ succeeded: boolean, value?: Root, errors?: string }
-
parseNebula(source, origin?, verbose?)- Parse arbitrary RIDDL definitions (nebula)
- A nebula is a collection of definitions that may not form a complete Root
- Parameters: Same as
parseString - Returns:
{ succeeded: boolean, value?: Nebula, errors?: string }
-
parseToTokens(source, origin?, verbose?)- Parse RIDDL source into tokens for syntax highlighting
- Fast, lenient parsing without full validation
- Parameters: Same as
parseString - Returns:
{ succeeded: boolean, value?: Token[], errors?: string }
-
createContext(showTimes?, showWarnings?, verbose?)- Create a custom platform context with specific options
- Parameters:
showTimes: boolean- Enable timing information (default: false)showWarnings: boolean- Include warnings in messages (default: true)verbose: boolean- Enable verbose output (default: false)
- Returns:
PlatformContext
-
formatMessages(messages)- Format error/warning messages as a human-readable string
- Parameters:
messages: Messages- The messages to format
- Returns:
string- Formatted messages separated by newlines
-
version(property)- Get the RIDDL library version
- Returns:
string- Version number
import { RiddlAPI } from '@ossuminc/riddl-lib';
// Basic parsing
const source = `
domain ShoppingCart is {
type Item is String
}
`;
const result = RiddlAPI.parseString(source, "example.riddl");
if (result.succeeded) {
console.log("✓ Parse successful");
const root = result.value;
// Work with the AST
} else {
console.error("✗ Parse failed:");
console.error(result.errors);
}
// Syntax highlighting
const tokens = RiddlAPI.parseToTokens(source);
if (tokens.succeeded) {
tokens.value.forEach(token => {
console.log(`${token.kind}: ${token.text}`);
});
} else {
console.error("Tokenization failed:", tokens.errors);
}
// Custom context
const context = RiddlAPI.createContext(true, true, false);
const result2 = RiddlAPI.parseStringWithContext(source, "test.riddl", false, context);
if (result2.succeeded) {
console.log("Custom context parse successful");
}
// Version info
console.log(`Using RIDDL ${RiddlAPI.version}`);For TypeScript projects, you can define the result interface:
interface ParseResult<T> {
succeeded: boolean;
value?: T;
errors?: string;
}
import { RiddlAPI } from '@ossuminc/riddl-lib';
const result = RiddlAPI.parseString("domain Example is { ??? }") as ParseResult<any>;
if (result.succeeded) {
console.log("Success:", result.value);
} else {
console.error("Error:", result.errors);
}The build script does the following:
- Gets the version from sbt (using git tags via dynver)
- Builds optimized JavaScript using Scala.js
fullOptJS - Creates
package.jsonfrom template - Creates
README.mdwith usage instructions - Runs
npm packto create a.tgztarball - Outputs packages to
npm-packages/directory
Output location: npm-packages/
Package naming: ossuminc-<module-name>-<version>.tgz
Example: ossuminc-riddl-lib-1.0.1-7-a3a42f2e.tgz
npm install /path/to/riddl/npm-packages/ossuminc-riddl-lib-*.tgz{
"dependencies": {
"@ossuminc/riddl-lib": "file:../riddl/npm-packages/ossuminc-riddl-lib-1.0.1-7-a3a42f2e.tgz"
}
}Then run:
npm install{
"dependencies": {
"@ossuminc/riddl-lib": "file:../riddl/npm-packages/ossuminc-riddl-lib-*.tgz"
}
}Note: Wildcard requires npm 7+ or using a symlink
When you make changes to RIDDL and want to update your project:
-
Rebuild the package:
cd /path/to/riddl ./scripts/pack-npm-modules.sh riddlLib -
Update in your project:
cd /path/to/your/project npm install /path/to/riddl/npm-packages/ossuminc-riddl-lib-*.tgz
Or if using
file:in package.json:rm -rf node_modules/@ossuminc npm install
The script uses fullOptJS for production-optimized builds. For faster development builds:
Edit the script and change line 48:
# Production (slower build, smaller output):
sbt -Dsbt.supershell=false "project ${module_js}" fullOptJS
# Development (faster build, larger output):
sbt -Dsbt.supershell=false "project ${module_js}" fastOptJSEach package contains:
package/
├── main.js # Compiled JavaScript
├── package.json # npm package metadata
└── README.md # Usage instructions
Error: ERROR: Package not found at /path/to/package.tgz
Solution: Check that npm pack succeeded. Run manually:
cd riddlLib/js/target/scala-3.4.3/riddl-lib-opt
npm packError: Wrong version in package.json
Solution: The version comes from git tags. Ensure:
git describe --tags --alwaysReturns expected version.
Error: ERROR: Build failed for module
Solution: Run sbt build manually to see errors:
sbt "project riddlLibJS" fullOptJSTo add support for a new module:
-
Create package.json.template:
cat > <module>/js/package.json.template << 'EOF' { "name": "@ossuminc/<module-name>", "version": "VERSION_PLACEHOLDER", "description": "RIDDL <Module> - JavaScript/TypeScript bindings", "main": "main.js", "type": "module", "exports": { ".": "./main.js" }, "keywords": ["riddl"], "author": "Ossum Inc.", "license": "Apache-2.0", "repository": { "type": "git", "url": "https://github.com/ossuminc/riddl.git" } } EOF
-
Add module to AVAILABLE_MODULES in
scripts/pack-npm-modules.sh:AVAILABLE_MODULES=("riddlLib" "utils" "passes" "diagrams" "language" "yourModule")
-
Build:
./scripts/pack-npm-modules.sh yourModule
Commit the .tgz files to a shared repository:
git add npm-packages/*.tgz
git commit -m "Add npm packages"
git pushThen team members can:
git pull
npm install npm-packages/ossuminc-riddl-lib-*.tgzCopy npm-packages/ directory to a shared location (network drive, S3, etc.):
# On build machine:
cp npm-packages/*.tgz /shared/drive/riddl-packages/
# On developer machine:
npm install /shared/drive/riddl-packages/ossuminc-riddl-lib-*.tgz| Feature | Maven (.m2/repository) | npm pack |
|---|---|---|
| Local install | mvn install |
npm pack + npm install |
| Location | ~/.m2/repository |
Project directory |
| Version management | Automatic | Manual (via git tags) |
| Sharing | Automatic via .m2 | Manual (copy .tgz files) |
| CI/CD friendly | ✅ Yes | ✅ Yes (with file paths) |
| Multiple versions | ✅ Yes |