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';
}
|