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         50x 50x 50x 50x 50x   50x   2x   2x                 2x                 2x 1x     2x 1x     2x       2x 2x       2x 2x 2x 2x 3x 3x 3x   2x 2x 2x         50x 50x     50x 50x     50x 3x 3x       50x 50x 50x 47x 47x 47x     50x    
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';
}