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

specml

v0.1.2

Published

A simple, powerful schema definition language for defining data structures and API specifications. Generate TypeScript types, JSDoc definitions, and OpenAPI/Swagger docs from a single source of truth.

Readme

SpecML

A simple, powerful schema definition language for defining data structures and API specifications. Generate TypeScript types, JSDoc definitions, and OpenAPI/Swagger docs from a single source of truth.

Installation

npm install specml

Usage

Command Line Interface

After installation, use the specml command:

# Generate TypeScript types
specml -ts types.spec -o types.d.ts

# Generate JSDoc definitions
specml --jsdoc types.spec -o types.jsdoc.js

# Generate OpenAPI/Swagger spec
specml -swagger api.spec -o openapi.json --title "My API"

# Generate Java Spring model classes
specml -java api.spec --out-dir ./src/main/java --package com.myapp.model

# Generate multiple formats at once
specml types.spec --ts --jsdoc --out-dir ./dist

# TypeScript with interfaces instead of types
specml -ts types.spec --interfaces -o types.d.ts

# OpenAPI with custom options
specml -swagger api.spec \
  --title "My API" \
  --version "2.0.0" \
  --server https://api.example.com \
  -o openapi.json

# Show help
specml --help

# Show version
specml --version

JavaScript API

You can also use SpecML programmatically:

JavaScript API

You can also use SpecML programmatically:

const specml = require('specml');

// Generate TypeScript types
specml.createTypes('./types.spec', {
  outputFile: './types.d.ts'
});

// Generate JSDoc definitions
specml.createJSDoc('./types.spec', {
  outputFile: './types.jsdoc.js'
});

// Generate OpenAPI/Swagger specification
specml.createSwagger('./api.spec', {
  title: 'My API',
  version: '1.0.0',
  outputFile: './openapi.json'
});

// Generate Java Spring model classes
specml.createJava('./api.spec', {
  packageName: 'com.myapp.model',
  outDir: './src/main/java'
});

What is SpecML?

SpecML is a line-based schema definition language designed to be simple, readable, and expressive. Define your data structures once and generate multiple outputs:

  • TypeScript type definitions
  • JSDoc type definitions
  • OpenAPI/Swagger 3.0 API specifications
  • Java Spring model classes

Design Philosophy

  • Line-based - Each declaration is on a single line
  • Readable - Clear syntax that looks like natural type definitions
  • Flexible - Supports references, aliases, arrays, enums, and nested structures
  • Validated - Rich set of built-in validators and modifiers

SpecML Syntax

Basic Structure

User {
  id string
  name string
  age number
  isActive boolean
}

Type System

Primitive types:

  • string - Text values
  • number - Numeric values (integers and floats)
  • boolean - True/false values
  • object - Generic objects
  • No type specified - Accepts any value

Optional Fields

Use ? to mark fields as optional:

User {
  email string        // Required
  phone? string       // Optional
  bio? string         // Optional
}

Arrays

Use [] for variable-length arrays, or [n] for fixed-length:

User {
  tags[] string           // One or more tags
  coordinates[2] number   // Exactly 2 numbers
  scores[10]? number      // Optional array of exactly 10 numbers
}

Nested Objects

Define nested structures inline:

User {
  name string
  address {
    street string
    city string
    zipCode string
  }
  contact {
    email string
    phone string
  }
}

Enums

Specify allowed values using parentheses:

User {
  role string(admin|user|guest)
  status string(active|inactive|pending)
}

Field Modifiers

Add validation constraints using <>:

User {
  email string<isEmail>
  age number<min:18|max:120>
  username string<minLength:3|maxLength:20>
  website? string<isUrl>
  id string<ulid>
  createdAt string<isISO>
}

References

Reference other types using #:

Address {
  street string
  city string
  zipCode string
}

User {
  name string
  homeAddress#Address
  workAddress#Address?
}

Aliases

Map input names to output names using ::

User {
  fname:firstName string
  lname:lastName string
  email:emailAddress string<isEmail>
}

Input accepts: fname, lname, email
Output produces: firstName, lastName, emailAddress

Comments

Use // for comments:

// User profile schema
User {
  id string<ulid>          // Unique identifier
  email string<isEmail>    // Must be valid email
  age number<min:13>       // Minimum age requirement
}

API Specifications (ASPECML)

SpecML can also define REST API endpoints using special field names:

CreateUserEndpoint {
  method POST
  path /api/users
  
  body {
    email string<isEmail>
    password string<minLength:8>
    username string<minLength:3>
  }
  
  response {
    success {
      status 201
      body {
        id string<ulid>
        email string
        username string
        createdAt string<isISO>
      }
    }
    
    validation_error {
      status 422
      body {
        error string
        details[] {
          field string
          message string
        }
      }
    }
  }
}

Endpoint Structure

Required fields:

  • method - HTTP method (GET, POST, PUT, PATCH, DELETE)
  • path - API route (use :param for path parameters)
  • response - Response scenarios with status codes

Optional fields:

  • headers - Request/response headers
  • query - Query string parameters
  • params - Path parameters
  • body - Request/response body

Supported Modifiers

| Modifier | Description | Example | |----------|-------------|---------| | isEmail | Valid email address | string<isEmail> | | isUrl | Valid URL | string<isUrl> | | isUUID | Valid UUID | string<isUUID> | | isISO | ISO 8601 date-time | string<isISO> | | ulid | ULID format | string<ulid> | | min | Minimum value | number<min:0> | | max | Maximum value | number<max:100> | | minLength | Minimum string length | string<minLength:3> | | maxLength | Maximum string length | string<maxLength:50> | | length | Exact length | string<length:6> | | pattern | Regex pattern | string<pattern:/^\d+$/> | | trim | Trim whitespace | string<trim> | | lowercase | Convert to lowercase | string<lowercase> | | uppercase | Convert to uppercase | string<uppercase> |

CLI Options

Format Options

  • -ts, --typescript, --ts - Generate TypeScript types
  • -jsdoc, --jsdoc - Generate JSDoc definitions
  • -swagger, --swagger, -openapi, --openapi - Generate OpenAPI/Swagger spec
  • -java, --java - Generate Java Spring model classes

Output Options

  • -o, --output <file> - Output file path (single format)
  • --out-dir <dir> - Output directory (multiple formats)

TypeScript Options

  • --interfaces - Use interfaces instead of types
  • --no-comments - Exclude JSDoc comments
  • --indent <size> - Indentation size (default: 2)

JSDoc Options

  • --no-examples - Exclude examples
  • --no-constraints - Exclude constraint documentation
  • --line-width <width> - Line width for wrapping (default: 80)

Swagger/OpenAPI Options

  • --title <title> - API title
  • --version <version> - API version (default: 1.0.0)
  • --description <desc> - API description
  • --server <url> - API server URL (can be used multiple times)

Java Options

  • --package <name> - Java package name (default: com.example.model)
  • --no-validation - Exclude Jakarta validation annotations
  • --no-jackson - Exclude Jackson annotations
  • --swagger-annotations - Include Swagger/OpenAPI annotations
  • --lombok - Use Lombok annotations
  • --builder - Include builder pattern

General Options

  • -h, --help - Show help message
  • -v, --version - Show version number
  • --verbose - Verbose output

JavaScript API

createTypes(specFilePath, options)

Generate TypeScript type definitions from a SpecML file.

Parameters:

  • specFilePath (string) - Path to the .spec file
  • options (object):
    • exportTypes (boolean) - Export types (default: true)
    • useInterfaces (boolean) - Use interfaces instead of types (default: false)
    • strictNullChecks (boolean) - Strict null checks (default: true)
    • includeComments (boolean) - Include JSDoc comments (default: true)
    • indentSize (number) - Indent size (default: 2)
    • outputFile (string) - Optional output file path

Returns: TypeScript type definitions string

Example:

const specml = require('specml');

const types = specml.createTypes('./models.spec', {
  useInterfaces: false,
  includeComments: true,
  outputFile: './types.d.ts'
});

createJSDoc(specFilePath, options)

Generate JSDoc type definitions from a SpecML file.

Parameters:

  • specFilePath (string) - Path to the .spec file
  • options (object):
    • includeExamples (boolean) - Include examples (default: true)
    • includeConstraints (boolean) - Include constraint documentation (default: true)
    • includeMetadata (boolean) - Include metadata tags (default: true)
    • indentSize (number) - Indent size (default: 2)
    • lineWidth (number) - Line width for wrapping (default: 80)
    • outputFile (string) - Optional output file path

Returns: JSDoc type definitions string

Example:

const jsdoc = specml.createJSDoc('./types.spec', {
  includeExamples: true,
  outputFile: './types.jsdoc.js'
});

createSwagger(specFilePath, options)

Generate OpenAPI/Swagger 3.0 specification from a SpecML file.

Parameters:

  • specFilePath (string) - Path to the .spec file
  • options (object):
    • title (string) - API title (default: 'API Documentation')
    • version (string) - API version (default: '1.0.0')
    • description (string) - API description
    • servers (array) - Server configurations
    • includeExamples (boolean) - Include examples (default: true)
    • outputFile (string) - Optional output file path

Returns: OpenAPI specification object

Example:

const swagger = specml.createSwagger('./api.spec', {
  title: 'My API',
  version: '1.0.0',
  servers: [{ url: 'https://api.example.com' }],
  outputFile: './openapi.json'
});

createJava(specFilePath, options)

Generate Java Spring model classes from a SpecML file.

Parameters:

  • specFilePath (string) - Path to the .spec file
  • options (object):
    • packageName (string) - Java package name (default: 'com.example.model')
    • outDir (string) - Output directory (required)
    • includeValidation (boolean) - Include Jakarta validation (default: true)
    • includeJackson (boolean) - Include Jackson annotations (default: true)
    • includeSwagger (boolean) - Include Swagger annotations (default: false)
    • includeLombok (boolean) - Use Lombok annotations (default: false)
    • includeBuilder (boolean) - Include builder pattern (default: false)

Returns: Map of class names to Java code

Example:

const classes = specml.createJava('./api.spec', {
  packageName: 'com.myapp.model',
  outDir: './src/main/java',
  includeValidation: true,
  includeSwagger: true
});

fromString(specString)

Parse a SpecML string directly (without file I/O).

Parameters:

  • specString (string) - The SpecML specification string

Returns: Object with methods:

  • toTypes(options) - Generate TypeScript types
  • toJSDoc(options) - Generate JSDoc definitions
  • toSwagger(options) - Generate OpenAPI spec
  • ast - The parsed AST

Example:

const spec = specml.fromString(`
  User {
    id string<ulid>
    email string<isEmail>
    role string(admin|user|guest)
  }
`);

const typescript = spec.toTypes();
const jsdoc = spec.toJSDoc();
const swagger = spec.toSwagger({ title: 'User API' });
const javaClasses = spec.toJava({ packageName: 'com.myapp.model' });

Examples

Type Definitions

types.spec:

User {
  id string<ulid>
  email string<isEmail>
  username string<minLength:3|maxLength:20>
  role string(admin|user|guest)
  profile {
    firstName string
    lastName string
    avatar? string<isUrl>
    bio? string<maxLength:500>
  }
  createdAt string<isISO>
  updatedAt string<isISO>
}

Product {
  id string<ulid>
  name string
  description? string
  price number<min:0>
  currency string(USD|EUR|GBP)
  inStock boolean
  tags[] string
  images[]? string<isUrl>
}

Generate TypeScript:

const specml = require('specml');

specml.createTypes('./types.spec', {
  outputFile: './types.d.ts'
});

Output (types.d.ts):

export type User = {
  /** Constraints: ulid */
  id: string;
  /** Constraints: isEmail */
  email: string;
  /** Constraints: minLength, maxLength */
  username: string;
  role: "admin" | "user" | "guest";
  profile: {
    firstName: string;
    lastName: string;
    /** Constraints: isUrl */
    avatar?: string;
    /** Constraints: maxLength */
    bio?: string;
  };
  /** Constraints: isISO */
  createdAt: string;
  /** Constraints: isISO */
  updatedAt: string;
};

export type Product = {
  /** Constraints: ulid */
  id: string;
  name: string;
  description?: string;
  /** Constraints: min */
  price: number;
  currency: "USD" | "EUR" | "GBP";
  inStock: boolean;
  tags: string[];
  /** Constraints: isUrl */
  images?: string[];
};

API Specification

api.spec:

CreateUserEndpoint {
  method POST
  path /api/users
  
  body {
    email string<isEmail|lowercase>
    password string<minLength:8>
    username string<minLength:3|maxLength:20>
  }
  
  response {
    success {
      status 201
      body {
        id string<ulid>
        email string
        username string
        createdAt string<isISO>
      }
    }
    
    validation_error {
      status 422
      body {
        error string
        details[] {
          field string
          message string
        }
      }
    }
  }
}

GetUserEndpoint {
  method GET
  path /api/users/:userId
  
  params {
    userId string<ulid>
  }
  
  response {
    success {
      status 200
      body {
        id string
        email string
        username string
      }
    }
    
    not_found {
      status 404
      body {
        error string
      }
    }
  }
}

Generate OpenAPI:

specml.createSwagger('./api.spec', {
  title: 'User API',
  version: '1.0.0',
  servers: [{ url: 'https://api.example.com' }],
  outputFile: './openapi.json'
});

Using Aliases for Field Mapping

request.spec:

CreateUserRequest {
  fname:firstName string<trim>
  lname:lastName string<trim>
  email:emailAddress string<isEmail|lowercase>
  pwd:password string<minLength:8>
}

Input accepts: fname, lname, email, pwd
Output produces: firstName, lastName, emailAddress, password

Using References for Reusability

models.spec:

Address {
  street string
  city string
  state string
  zipCode string
}

ContactInfo {
  email string<isEmail>
  phone string
}

User {
  id string<ulid>
  name string
  contact#ContactInfo
  homeAddress#Address
  workAddress#Address?
}

Build Script Integration

build.js:

const specml = require('specml');

// Generate TypeScript types
specml.createTypes('./specs/models.spec', {
  outputFile: './src/types.d.ts'
});

// Generate JSDoc
specml.createJSDoc('./specs/models.spec', {
  outputFile: './src/types.jsdoc.js'
});

// Generate OpenAPI spec
specml.createSwagger('./specs/api.spec', {
  title: 'My API',
  version: process.env.API_VERSION || '1.0.0',
  outputFile: './docs/openapi.json'
});

// Generate Java models
specml.createJava('./specs/models.spec', {
  packageName: 'com.myapp.model',
  outDir: './src/main/java'
});

console.log('✓ All specifications generated');

package.json:

{
  "scripts": {
    "build:specs": "node build.js",
    "prebuild": "npm run build:specs"
  }
}

Advanced Features

Declaration Order

SpecML follows a specific order for declaration components:

baseName#reference:alias[length]?

Examples:

// Just baseName
name string

// baseName + reference
contact#Person

// baseName + reference + alias
contact#Person:primaryContact

// baseName + alias + array
tags:categories[] string

// baseName + reference + alias + array
items#Product:productList[]

// All components
owners#Person:administrators[]?

Chained References

Reference nested types using multiple #:

Company {
  Locations {
    Headquarters {
      city string
      country string
    }
  }
}

Branch {
  location#Company#Locations#Headquarters
}

Quoted Names

Use quotes for field names with spaces or special characters:

APIResponse {
  "Content-Type" string
  "X-Request-ID" string<ulid>
  "User Name" string
}

Learn More

For complete SpecML syntax documentation, see:

License

MIT