or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-validation.mderror-handling.mdindex.mdjtd-schemas.mdkeywords-vocabularies.mdschema-2019.mdschema-2020.mdschema-management.mdstandalone-generation.mdtypescript-integration.md
tile.json

standalone-generation.mddocs/

Standalone Code Generation

Generate standalone validation functions that don't require the Ajv runtime for deployment optimization, reduced bundle sizes, and self-contained validation logic.

Capabilities

Standalone Code Function

Generates standalone JavaScript code for validation functions that can run independently without the Ajv library.

/**
 * Generates standalone validation code
 * @param ajv - Ajv instance with code.source option enabled
 * @param refsOrFunc - Validation function, mapping of refs to validation functions, or undefined for all schemas
 * @returns Self-contained JavaScript code as string
 */
function standaloneCode(
  ajv: AjvCore,
  refsOrFunc?: {[K in string]?: string} | AnyValidateFunction
): string;

Usage Examples:

import Ajv from "ajv";
import standaloneCode from "ajv/dist/standalone";

const ajv = new Ajv({ code: { source: true, esm: true } });

// Simple schema
const schema = {
  type: "object",
  properties: {
    name: { type: "string" },
    age: { type: "number", minimum: 0 }
  },
  required: ["name", "age"],
  additionalProperties: false
};

// Compile validation function
const validate = ajv.compile(schema);

// Generate standalone code
const moduleCode = standaloneCode(ajv, validate);

console.log(moduleCode);
/* Generated code will be similar to:
export const validate = (function() {
  "use strict";
  const schema0 = {"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number","minimum":0}},"required":["name","age"],"additionalProperties":false};
  
  return function validate(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}) {
    let vErrors = null;
    let errors = 0;
    
    if (!(data && typeof data == "object" && !Array.isArray(data))) {
      const err0 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};
      if (vErrors === null) vErrors = [err0];
      else vErrors.push(err0);
      errors++;
    }
    
    // ... rest of validation logic
    
    validate.errors = vErrors;
    return errors === 0;
  };
})();
export default validate;
*/

Multiple Validation Functions

Generate standalone code for multiple validation functions in a single module.

/**
 * Generates standalone code for multiple validation functions
 * @param ajv - Ajv instance with code.source option enabled
 * @param refs - Object mapping schema keys/refs to export names
 * @returns Module code with multiple exported validation functions
 */
function standaloneCode(
  ajv: AjvCore,
  refs: {[schemaKeyRef: string]: string}
): string;

Usage Examples:

import Ajv from "ajv";
import standaloneCode from "ajv/dist/standalone";

const ajv = new Ajv({ code: { source: true, esm: true } });

// Define multiple schemas
const userSchema = {
  type: "object",
  properties: {
    id: { type: "integer" },
    name: { type: "string" },
    email: { type: "string", format: "email" }
  },
  required: ["id", "name", "email"]
};

const productSchema = {
  type: "object",
  properties: {
    id: { type: "string" },
    name: { type: "string" },
    price: { type: "number", minimum: 0 },
    category: { enum: ["electronics", "clothing", "books"] }
  },
  required: ["id", "name", "price"]
};

const orderSchema = {
  type: "object",
  properties: {
    id: { type: "string" },
    userId: { type: "integer" },
    items: {
      type: "array",
      items: {
        type: "object",
        properties: {
          productId: { type: "string" },
          quantity: { type: "integer", minimum: 1 }
        },
        required: ["productId", "quantity"]
      }
    },
    total: { type: "number", minimum: 0 }
  },
  required: ["id", "userId", "items", "total"]
};

// Compile validation functions
const validateUser = ajv.compile(userSchema);
const validateProduct = ajv.compile(productSchema);
const validateOrder = ajv.compile(orderSchema);

// Generate standalone module with multiple functions
const moduleCode = standaloneCode(ajv, {
  validateUser,
  validateProduct,
  validateOrder
});

// Write to file for deployment
import { writeFileSync } from "fs";
writeFileSync("./dist/validators.js", moduleCode);

/* Generated module exports:
export const validateUser = function(data) { ... };
export const validateProduct = function(data) { ... };
export const validateOrder = function(data) { ... };
*/

Code Generation Options

Control the output format and features of generated standalone code.

/**
 * Code generation options for standalone output
 */
interface CodeOptions {
  /** Generate source code mappings - required for standalone code */
  source?: boolean;
  
  /** Output ES modules (import/export) instead of CommonJS */
  esm?: boolean;
  
  /** Include line numbers in generated code */
  lines?: boolean;
  
  /** Optimize generated code (0=none, 1=basic, 2=advanced) */
  optimize?: boolean | number;
  
  /** Use ES5 compatible syntax */
  es5?: boolean;
  
  /** Code to require formats map (for standalone) */
  formats?: Code;
  
  /** Post-process generated code */
  process?: (code: string, schema?: SchemaEnv) => string;
  
  /** Regular expression engine */
  regExp?: RegExpEngine;
}

Usage Examples:

import Ajv from "ajv";
import standaloneCode from "ajv/dist/standalone";

// Different output formats
const ajvESM = new Ajv({
  code: {
    source: true,    // Include source mappings
    esm: true,       // ES module format
    lines: true,     // Include line numbers
    optimize: true,  // Optimize code
    format: true     // Format for readability
  }
});

const ajvCommonJS = new Ajv({
  code: {
    source: true,
    esm: false,      // CommonJS format
    es5: true,       // ES5 compatible
    optimize: false  // Keep all variables for debugging
  }
});

const schema = {
  type: "object",
  properties: {
    id: { type: "string" },
    value: { type: "number" }
  }
};

// Generate ES module
const validateESM = ajvESM.compile(schema);
const esmCode = standaloneCode(ajvESM, validateESM);
console.log("ES Module format:");
console.log(esmCode);

// Generate CommonJS module
const validateCJS = ajvCommonJS.compile(schema);
const cjsCode = standaloneCode(ajvCommonJS, validateCJS);
console.log("CommonJS format:");
console.log(cjsCode);

Integration with Build Systems

Examples of integrating standalone code generation into build processes.

/**
 * Build integration utilities
 */
interface BuildIntegration {
  /** Generate validation modules during build */
  generateValidators(schemas: Record<string, AnySchema>, outputDir: string): void;
  
  /** Watch schemas and regenerate on changes */
  watchSchemas(schemaDir: string, outputDir: string): void;
}

Usage Examples:

// build-validators.js - Build script
import Ajv from "ajv";
import standaloneCode from "ajv/dist/standalone";
import { writeFileSync, readFileSync, mkdirSync } from "fs";
import { join, dirname } from "path";

interface SchemaDefinition {
  name: string;
  schema: any;
  outputPath: string;
}

class ValidatorBuilder {
  private ajv: Ajv;
  
  constructor() {
    this.ajv = new Ajv({
      code: { source: true, esm: true, optimize: true },
      strict: true
    });
  }
  
  generateValidators(schemas: SchemaDefinition[]) {
    const validationFunctions: Record<string, any> = {};
    
    // Compile all schemas
    schemas.forEach(({ name, schema }) => {
      validationFunctions[name] = this.ajv.compile(schema);
    });
    
    // Generate standalone code
    const code = standaloneCode(this.ajv, validationFunctions);
    
    // Write to output file
    const outputPath = "./dist/validators.js";
    mkdirSync(dirname(outputPath), { recursive: true });
    writeFileSync(outputPath, code);
    
    console.log(`Generated validators: ${outputPath}`);
  }
  
  generateIndividualValidators(schemas: SchemaDefinition[]) {
    schemas.forEach(({ name, schema, outputPath }) => {
      const validate = this.ajv.compile(schema);
      const code = standaloneCode(this.ajv, validate);
      
      mkdirSync(dirname(outputPath), { recursive: true });
      writeFileSync(outputPath, code);
      
      console.log(`Generated ${name}: ${outputPath}`);
    });
  }
}

// Usage in build script
const builder = new ValidatorBuilder();

const schemas: SchemaDefinition[] = [
  {
    name: "validateUser",
    schema: JSON.parse(readFileSync("./schemas/user.json", "utf8")),
    outputPath: "./dist/validators/user.js"
  },
  {
    name: "validateProduct", 
    schema: JSON.parse(readFileSync("./schemas/product.json", "utf8")),
    outputPath: "./dist/validators/product.js"
  }
];

// Generate all validators
builder.generateValidators(schemas);

// Or generate individual files
builder.generateIndividualValidators(schemas);

Runtime Integration

Using generated standalone validators in production applications.

/**
 * Runtime usage of standalone validators
 */
interface StandaloneValidator {
  (data: unknown): boolean;
  errors?: ErrorObject[] | null;
}

Usage Examples:

// Using generated standalone validator
import { validateUser, validateProduct, validateOrder } from "./dist/validators.js";

// API endpoint using standalone validator
export async function createUser(req: Request, res: Response) {
  const userData = req.body;
  
  // Validate with standalone function (no Ajv runtime needed)
  if (!validateUser(userData)) {
    return res.status(400).json({
      error: "Validation failed",
      details: validateUser.errors
    });
  }
  
  // Process valid user data
  const user = await userService.create(userData);
  res.json(user);
}

// Middleware for request validation
function validateRequest(validator: StandaloneValidator) {
  return (req: Request, res: Response, next: NextFunction) => {
    if (!validator(req.body)) {
      return res.status(400).json({
        error: "Invalid request data",
        errors: validator.errors
      });
    }
    next();
  };
}

// Use validation middleware
app.post("/users", validateRequest(validateUser), createUser);
app.post("/products", validateRequest(validateProduct), createProduct);
app.post("/orders", validateRequest(validateOrder), createOrder);

Performance Benefits

Standalone validation provides significant performance advantages:

Bundle Size Reduction

// Without standalone: Include full Ajv library (~200KB)
import Ajv from "ajv";
const ajv = new Ajv();
const validate = ajv.compile(schema);

// With standalone: Only validation logic (~2-10KB per validator)
import { validateUser } from "./validators.js";

Runtime Performance

// Benchmark comparison
import Ajv from "ajv";
import standaloneCode from "ajv/dist/standalone";

const ajv = new Ajv();
const schema = { /* complex schema */ };

// Runtime compilation approach
const runtimeValidate = ajv.compile(schema);

// Standalone approach
const standaloneValidate = eval(standaloneCode(ajv, ajv.compile(schema)));

// Performance test
const testData = { /* test data */ };

console.time("Runtime validation");
for (let i = 0; i < 100000; i++) {
  runtimeValidate(testData);
}
console.timeEnd("Runtime validation");

console.time("Standalone validation");  
for (let i = 0; i < 100000; i++) {
  standaloneValidate(testData);
}
console.timeEnd("Standalone validation");

// Standalone is typically 10-30% faster due to:
// - No runtime schema resolution
// - Direct function calls
// - Optimized code paths
// - Reduced memory allocations

Deployment Optimization

// Optimized deployment structure
/*
dist/
├── validators/
│   ├── user.js      (standalone user validator)
│   ├── product.js   (standalone product validator)
│   └── order.js     (standalone order validator)
├── api/
│   ├── users.js     (uses validators/user.js)
│   ├── products.js  (uses validators/product.js)
│   └── orders.js    (uses validators/order.js)
└── main.js          (no Ajv dependency needed)
*/

// Each validator is self-contained and optimized
// Total validation bundle: ~50KB vs ~200KB+ with runtime Ajv