zap-lang
TypeScript icon, indicating that this package has built-in type declarations

1.0.5 • Public • Published

Zap Lang Package

A TypeScript utility library for parsing, validating, and transforming Zap Lang API collection files. It enables filesystem-first, portable, and human-readable API collections for use in VS Code, CLI, or browser-based API testing and automation tools.

Features

  • Parse and validate Zap Lang files (api-collection, api-folder, api-request, api-global, api-environment)
  • File System Discovery Mode: No items arrays required; hierarchy is inferred from directory structure
  • Variable resolution and merging across all scopes (global, environment, collection, folder, request, session)
  • Transforms Zap requests to Axios-compatible config objects (no Axios dependency - axios is dev dependency only)
  • Supports HTTP, GraphQL, WebSocket, and File operations (protocol is inferred by structure, not a type field in request)
  • Web-compatible build - works in browser environments like VS Code workbench
  • Comprehensive test coverage with real sample collections and live API execution
  • Strictly follows the Zap Lang Specification

Test Coverage

  • 56 passing tests covering all functionality
  • Live API execution tests against JSONPlaceholder API
  • End-to-end validation of all sample collection files
  • Variable resolution at all scopes (collection, folder, request)
  • Axios conversion for all HTTP methods (GET, POST, PUT, DELETE)
  • Error handling and edge cases

Installation

npm install zap-lang

Quick Start

Basic Parsing and Validation

import { parseZap, validateZapObject } from 'zap-lang';

// Parse a Zap Lang file
const zapFileContent = `{
  "zapType": "api-request",
  "zapVersion": 1,
  "meta": { "name": "Get Users" },
  "request": {
    "method": "GET",
    "url": "{{baseUrl}}/users",
    "headers": [
      { "name": "Authorization", "value": "Bearer {{token}}" }
    ]
  }
}`;

const result = parseZap(zapFileContent);
if (result.validation.valid) {
  console.log('Valid Zap request:', result.object);
} else {
  console.error('Validation errors:', result.validation.errors);
}

Variable Merging

import { mergeZapVariables } from 'zap-lang';

const variables = mergeZapVariables({
  global: { zapType: 'api-global', zapVersion: 1, variables: { timeout: 5000 } },
  environment: { zapType: 'api-environment', zapVersion: 1, variables: { baseUrl: 'https://api.dev.example.com' } },
  collection: { zapType: 'api-collection', zapVersion: 1, meta: { name: 'Users' }, variables: { version: 'v1' } },
  sessionVars: { token: 'abc123' }
});
// Result: { timeout: 5000, baseUrl: 'https://api.dev.example.com', version: 'v1', token: 'abc123' }

Converting to Axios Config

import { zapRequestToAxiosConfig } from 'zap-lang';

const zapRequest = {
  zapType: 'api-request',
  zapVersion: 1,
  meta: { name: 'Create User' },
  request: {
    method: 'POST',
    url: '{{baseUrl}}/users',
    headers: [
      { name: 'Content-Type', value: 'application/json' },
      { name: 'Authorization', value: 'Bearer {{token}}' }
    ],
    body: {
      type: 'json',
      content: '{"name": "{{userName}}", "email": "{{userEmail}}"}'
    }
  }
};

const variables = {
  baseUrl: 'https://api.example.com',
  token: 'abc123',
  userName: 'John Doe',
  userEmail: 'john@example.com'
};

const axiosConfig = zapRequestToAxiosConfig(zapRequest, variables);
// Result: Ready-to-use Axios config object
console.log(axiosConfig);
// {
//   method: 'post',
//   url: 'https://api.example.com/users',
//   headers: {
//     'Content-Type': 'application/json',
//     'Authorization': 'Bearer abc123'
//   },
//   data: {
//     name: 'John Doe',
//     email: 'john@example.com'
//   }
// }

File System Discovery

import { loadZapFiles, getAllRequests, mergeZapVariables } from 'zap-lang';

// Load all .zap files from a directory structure
const files = loadZapFiles('./my-api-collection');
// Returns a flat object with all parsed .zap files keyed by relative path

// Get all requests from the loaded files
const requests = getAllRequests(files);

// Example: Execute all requests in a collection
for (const [path, request] of Object.entries(requests)) {
  const variables = mergeZapVariables({
    collection: files['collection.zap'],
    request: request,
    sessionVars: { token: 'your-token' }
  });
  
  const axiosConfig = zapRequestToAxiosConfig(request, variables);
  // Execute with axios: await axios(axiosConfig)
}

API Reference

Parsing Functions

parseZap(content: string): ZapParseResult

Parses a JSON string into a validated Zap object.

const result = parseZap('{"zapType": "api-request", ...}');
if (result.validation.valid) {
  console.log(result.object); // Parsed Zap object
} else {
  console.log(result.validation.errors); // Validation errors
}

Returns: { object: ZapObject | null, validation: ZapValidationResult }

serializeZap(obj: ZapObject, indent?: number): string

Serializes a Zap object to a JSON string.

const json = serializeZap(zapObject, 2); // Pretty-printed with 2-space indent

isValidZapString(content: string): boolean

Quick check if a string contains valid Zap Lang JSON.

if (isValidZapString(fileContent)) {
  // Safe to parse
}

Validation Functions

validateZapObject(obj: any): ZapValidationResult

Validates any object against Zap Lang schema.

const validation = validateZapObject(someObject);
if (validation.valid) {
  // Object is valid
} else {
  console.log(validation.errors); // Array of error messages
}

Returns: { valid: boolean, errors: string[] }

isValidZapObject(obj: any): boolean

Quick boolean check for object validity.

if (isValidZapObject(obj)) {
  // Object is valid
}

Creator Functions

createApiRequest(options: Partial<ZapApiRequest>): ZapApiRequest

Creates a new API request object with defaults.

const request = createApiRequest({
  meta: { name: 'Get Users' },
  request: {
    method: 'GET',
    url: '{{baseUrl}}/users'
  }
});

createApiCollection(options: Partial<ZapApiCollection>): ZapApiCollection

Creates a new API collection object.

const collection = createApiCollection({
  meta: { name: 'My API Collection' },
  variables: { baseUrl: 'https://api.example.com' }
});

createApiFolder(options: Partial<ZapApiFolder>): ZapApiFolder

Creates a new API folder object.

const folder = createApiFolder({
  meta: { name: 'User Management' },
  variables: { endpoint: '/users' }
});

createApiEnvironment(options: Partial<ZapApiEnvironment>): ZapApiEnvironment

Creates a new environment object.

const env = createApiEnvironment({
  meta: { name: 'Development' },
  variables: { baseUrl: 'https://api.dev.example.com' }
});

createApiGlobal(options: Partial<ZapApiGlobal>): ZapApiGlobal

Creates a new global variables object.

const global = createApiGlobal({
  variables: { timeout: 5000, retries: 3 }
});

Variable Functions

mergeZapVariables(options: MergeVariablesOptions): Record<string, any>

Merges variables from all scopes with proper precedence.

const variables = mergeZapVariables({
  global: globalVarsObject,        // Lowest precedence
  environment: environmentObject,
  collection: collectionObject,
  folder: folderObject,
  request: requestObject,
  sessionVars: { token: 'abc123' } // Highest precedence
});

Precedence (lowest to highest): global → environment → collection → folder → request → session

replaceVariables(template: string, variables: Record<string, any>): string

Replaces {{variable}} placeholders in a string.

const url = replaceVariables('{{baseUrl}}/users/{{userId}}', {
  baseUrl: 'https://api.example.com',
  userId: '123'
});
// Result: 'https://api.example.com/users/123'

extractVariables(template: string): string[]

Extracts variable names from a template string.

const vars = extractVariables('{{baseUrl}}/users/{{userId}}');
// Result: ['baseUrl', 'userId']

Discovery Functions

loadZapFiles(directory: string): Record<string, ZapObject>

Loads all .zap files from a directory tree.

const files = loadZapFiles('./my-collection');
// Result: { 'folder/request.zap': requestObject, ... }

filterZapObjectsByType<T>(objects: Record<string, ZapObject>, zapType: ZapType): Record<string, T>

Filters loaded objects by type.

const requests = filterZapObjectsByType(files, 'api-request');
const collections = filterZapObjectsByType(files, 'api-collection');

findCollectionRoot(objects: Record<string, ZapObject>): ZapApiCollection | null

Finds the root collection object.

const rootCollection = findCollectionRoot(files);

getAllRequests(objects: Record<string, ZapObject>): Record<string, ZapApiRequest>

Gets all request objects from loaded files.

const requests = getAllRequests(files);

getAllFolders(objects: Record<string, ZapObject>): Record<string, ZapApiFolder>

Gets all folder objects from loaded files.

const folders = getAllFolders(files);

getEnvironments(objects: Record<string, ZapObject>): Record<string, ZapApiEnvironment>

Gets all environment objects.

const environments = getEnvironments(files);

getGlobalVariables(objects: Record<string, ZapObject>): ZapApiGlobal | null

Gets the global variables object.

const global = getGlobalVariables(files);

findAllRequests(obj: ZapObject): ZapApiRequest[]

Recursively finds all requests within a collection or folder.

const requests = findAllRequests(collectionObject);

Axios Adapter

zapRequestToAxiosConfig(zapRequest: ZapApiRequest, variables: Record<string, any>): AxiosRequestConfig

Converts a Zap request to an Axios-compatible configuration object.

const axiosConfig = zapRequestToAxiosConfig(zapRequest, variables);
// Use with axios: axios(axiosConfig)

Features:

  • Handles all HTTP methods (GET, POST, PUT, DELETE, PATCH, etc.)
  • Processes all body types (json, raw, form, urlencoded, binary, graphql)
  • Converts headers array to object format
  • Applies variable substitution
  • Handles authentication (Bearer, Basic, API Key)
  • Sets appropriate content-type headers

Utility Exports

ZAP_LANG_VERSION: string

The current version of this zap-lang package.

ZAP_SPEC_VERSION: number

The Zap Lang specification version supported (currently 1).

Advanced Examples

Complete End-to-End Workflow

import { 
  loadZapFiles, 
  getAllRequests, 
  mergeZapVariables, 
  zapRequestToAxiosConfig,
  getEnvironments,
  getGlobalVariables 
} from 'zap-lang';
import axios from 'axios';

// 1. Load collection from filesystem
const files = loadZapFiles('./my-api-collection');

// 2. Get environment and global variables
const environments = getEnvironments(files);
const global = getGlobalVariables(files);
const environment = environments['development.zap']; // or user selection

// 3. Get all requests
const requests = getAllRequests(files);

// 4. Execute a specific request
async function executeRequest(requestPath: string, sessionVars: Record<string, any> = {}) {
  const request = requests[requestPath];
  if (!request) throw new Error(`Request not found: ${requestPath}`);

  // Merge variables from all scopes
  const variables = mergeZapVariables({
    global,
    environment,
    collection: files['collection.zap'],
    request,
    sessionVars
  });

  // Convert to axios config
  const axiosConfig = zapRequestToAxiosConfig(request, variables);

  // Execute the request
  try {
    const response = await axios(axiosConfig);
    console.log(`✅ ${request.meta.name}:`, response.status, response.data);
    return response;
  } catch (error) {
    console.error(`❌ ${request.meta.name}:`, error.message);
    throw error;
  }
}

// Execute requests
await executeRequest('users/create-user.zap', { 
  userName: 'John Doe',
  userEmail: 'john@example.com' 
});

Creating Collections Programmatically

import { 
  createApiCollection, 
  createApiFolder, 
  createApiRequest,
  serializeZap 
} from 'zap-lang';

// Create a new collection
const collection = createApiCollection({
  meta: { 
    name: 'Users API',
    description: 'CRUD operations for user management'
  },
  variables: {
    baseUrl: 'https://api.example.com',
    version: 'v1'
  }
});

// Create a folder
const usersFolder = createApiFolder({
  meta: { name: 'User Operations' },
  variables: { endpoint: '/users' }
});

// Create requests
const createUserRequest = createApiRequest({
  meta: { name: 'Create User' },
  request: {
    method: 'POST',
    url: '{{baseUrl}}/{{version}}{{endpoint}}',
    headers: [
      { name: 'Content-Type', value: 'application/json' },
      { name: 'Authorization', value: 'Bearer {{token}}' }
    ],
    body: {
      type: 'json',
      content: JSON.stringify({
        name: '{{userName}}',
        email: '{{userEmail}}'
      })
    }
  }
});

// Serialize to JSON
console.log(serializeZap(collection, 2));
console.log(serializeZap(createUserRequest, 2));

Dynamic Variable Resolution

import { mergeZapVariables, replaceVariables, extractVariables } from 'zap-lang';

// Complex variable merging with session state
const variables = mergeZapVariables({
  global: { timeout: 5000, retries: 3 },
  environment: { baseUrl: 'https://api.dev.example.com' },
  collection: { version: 'v1' },
  folder: { endpoint: '/users' },
  request: { userId: '{{createdUserId}}' }, // Dynamic from previous request
  sessionVars: { 
    token: 'session-token',
    createdUserId: '12345' // From previous request response
  }
});

// Template processing
const urlTemplate = '{{baseUrl}}/{{version}}{{endpoint}}/{{userId}}';
const resolvedUrl = replaceVariables(urlTemplate, variables);
console.log(resolvedUrl); // 'https://api.dev.example.com/v1/users/12345'

// Find missing variables
const requiredVars = extractVariables('{{baseUrl}}/{{version}}/{{missingVar}}');
const missingVars = requiredVars.filter(v => !(v in variables));
if (missingVars.length > 0) {
  console.warn('Missing variables:', missingVars);
}

GraphQL Request Example

const graphqlRequest = createApiRequest({
  meta: { name: 'Get User Profile' },
  request: {
    url: '{{graphqlEndpoint}}',
    headers: [
      { name: 'Content-Type', value: 'application/json' },
      { name: 'Authorization', value: 'Bearer {{token}}' }
    ],
    body: {
      type: 'graphql',
      content: `
        query GetUser($userId: ID!) {
          user(id: $userId) {
            id
            name
            email
            profile {
              avatar
              bio
            }
          }
        }
      `
    }
  },
  variables: {
    userId: '{{currentUserId}}'
  }
});

// Convert to axios config
const axiosConfig = zapRequestToAxiosConfig(graphqlRequest, {
  graphqlEndpoint: 'https://api.example.com/graphql',
  token: 'your-token',
  currentUserId: '123'
});

// The body will be properly formatted as:
// { query: "...", variables: { userId: "123" } }

Request Types

The package automatically detects request types based on structure:

  • HTTP Request: Has method and url fields
  • GraphQL Request: Has url and body.type: 'graphql' fields
  • WebSocket Request: Has url and wsMessage fields
  • File Request: Has fileOp field

Body Types

Supported body types in requests:

  • { type: 'json', content: '...' } - JSON content
  • { type: 'raw', content: '...' } - Raw text content
  • { type: 'form', form: [{ name: '...', value: '...' }] } - Form data
  • { type: 'urlencoded', urlencoded: [{ name: '...', value: '...' }] } - URL-encoded form
  • { type: 'binary', file: '...' } - Binary file
  • { type: 'none' } - No body
  • { type: 'graphql', content: '...' } - GraphQL query

Development

# Install dependencies
npm install

# Run tests
npm test

# Build for production
npm run build

# Build for Node.js environment
npm run build:node

# Development mode with watch
npm run dev

Browser Compatibility

This package is built for browser environments and works in:

  • VS Code workbench/webview environment
  • Modern browsers (ES2020+)
  • Node.js 16+ (with node build)

What this package does NOT do

  • Does NOT perform HTTP requests (no fetch/axios runtime dependency)
  • Does NOT manage request execution or test running
  • Does NOT provide CLI tools (focused on library functionality)
  • Does NOT require Node.js specific APIs (web-compatible)

Testing

The package includes comprehensive tests covering:

  • Parsing and validation of all Zap Lang object types
  • Variable merging and precedence
  • Axios adapter functionality
  • File system discovery
  • Real-world sample collections

License

MIT

Package Sidebar

Install

npm i zap-lang

Weekly Downloads

0

Version

1.0.5

License

MIT

Unpacked Size

340 kB

Total Files

10

Last publish

Collaborators

  • varun1257