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.
Maintainers
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 specmlUsage
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 --versionJavaScript 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 valuesnumber- Numeric values (integers and floats)boolean- True/false valuesobject- 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:paramfor path parameters)response- Response scenarios with status codes
Optional fields:
headers- Request/response headersquery- Query string parametersparams- Path parametersbody- 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 fileoptions(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 fileoptions(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 fileoptions(object):title(string) - API title (default: 'API Documentation')version(string) - API version (default: '1.0.0')description(string) - API descriptionservers(array) - Server configurationsincludeExamples(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 fileoptions(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 typestoJSDoc(options)- Generate JSDoc definitionstoSwagger(options)- Generate OpenAPI specast- 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:
- specml.md - Full SpecML language specification
- aspecml.md - API specification guide (ASPECML)
License
MIT
