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