All files print-ck.ts

67.14% Statements 47/70
64.19% Branches 52/81
100% Functions 3/3
78.84% Lines 41/52

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96            1x         45x 45x 45x 45x 45x   45x   2x   2x                 2x                 2x 1x     2x 1x     2x       2x 2x       2x 2x 2x 2x 3x 3x 3x   2x 2x 2x         45x 45x     45x 45x     45x 3x 3x       45x 45x 45x 42x 42x 42x     45x    
import type { CkRootNode, OpResponseHeaderNode } from '@contractkit/core';
import { printModelDecl } from './print-contract.js';
import { printRoute, printSecurity, type CommentBlock } from './print-operation.js';
import { printType } from './print-type.js';
import { INDENT } from './indent.js';
 
export const DEFAULT_PRINT_WIDTH = 80;
 
// ─── Options block ──────────────────────────────────────────────────────────
 
function printOptionsBlock(ast: CkRootNode): string | null {
    const hasMeta = Object.keys(ast.meta).length > 0;
    const hasServices = Object.keys(ast.services).length > 0;
    const hasSecurity = ast.security !== undefined;
    const hasRequestHeaders = (ast.requestHeaders?.length ?? 0) > 0;
    const hasResponseHeaders = (ast.responseHeaders?.length ?? 0) > 0;
 
    if (!hasMeta && !hasServices && !hasSecurity && !hasRequestHeaders && !hasResponseHeaders) return null;
 
    const lines: string[] = ['options {'];
 
    Iif (hasMeta) {
        lines.push(`${INDENT}keys: {`);
        for (const [key, value] of Object.entries(ast.meta)) {
            const v = value.startsWith('#') || value.includes(' ') ? `"${value}"` : value;
            lines.push(`${INDENT}${INDENT}${key}: ${v}`);
        }
        lines.push(`${INDENT}}`);
    }
 
    Iif (hasServices) {
        lines.push(`${INDENT}services: {`);
        for (const [key, value] of Object.entries(ast.services)) {
            const v = value.startsWith('#') || value.includes(' ') ? `"${value}"` : value;
            lines.push(`${INDENT}${INDENT}${key}: ${v}`);
        }
        lines.push(`${INDENT}}`);
    }
 
    if (hasRequestHeaders) {
        lines.push(...printOptionsHeaderScope('request', ast.requestHeaders!));
    }
 
    if (hasResponseHeaders) {
        lines.push(...printOptionsHeaderScope('response', ast.responseHeaders!));
    }
 
    Iif (hasSecurity) {
        lines.push(...printSecurity(ast.security!, INDENT, INDENT + INDENT));
    }
 
    lines.push('}');
    return lines.join('\n');
}
 
function printOptionsHeaderScope(keyword: 'request' | 'response', headers: OpResponseHeaderNode[]): string[] {
    const I2 = INDENT + INDENT;
    const I3 = INDENT + INDENT + INDENT;
    const lines = [`${INDENT}${keyword}: {`, `${I2}headers: {`];
    for (Iconst h of headers) {
        const opt = h.optional ? '?' : '';
        const trail = h.description ? ` # ${h.description}` : '';
        lines.push(`${I3}${h.name}${opt}: ${printType(h.type)}${trail}`);
    }
    lines.push(`${I2}}`);
    lines.push(`${INDENT}}`);
    return lines;
}
 
// ─── CK file printer ───────────────────────────────────────────────────────
 
export function printCk(ast: CkRootNode, printWidth: number = DEFAULT_PRINT_WIDTH): string {
    const parts: string[] = [];
 
    // Options block
    const options = printOptionsBlock(ast);
    if (options) parts.push(options);
 
    // Contracts (models)
    for (Iconst model of ast.models) {
        Iif (parts.length > 0) parts.push('');
        parts.push(`contract ${printModelDecl(model, printWidth)}`);
    }
 
    // Operations (routes)
    const emptyBlocks: CommentBlock[] = [];
    const emptyIdx = { value: 0 };
    for (Iconst route of ast.routes) {
        if (parts.length > 0) parts.push('');
        const modPart = route.modifiers?.length ? `(${route.modifiers[0]})` : '';
        parts.push(`operation${modPart} ${printRoute(route, emptyBlocks, emptyIdx, Infinity)}`);
    }
 
    return parts.join('\n') + '\n';
}