Files
zen/bindings/nodejs/test/ts-support.spec.ts

77 lines
2.8 KiB
TypeScript

import { describe, expect, it } from '@jest/globals';
import * as tsc from 'typescript';
import { Workspace } from '../index';
import { createFunctionChecker, createTypeResolver, variableTypeToTs } from '../ts-support';
const SOURCE = `enum Level { Basic = 'basic', Premium = 'premium' }
type Region = 'EU' | 'US';
interface Extra { note: string; }
export const handler = async (input: FunctionInput) => {
return {
level: input.total > 500 ? Level.Premium : Level.Basic,
region: 'EU' as Region,
score: Math.round(input.total / 10),
extra: { note: 'hi' } as Extra,
};
};`;
const INPUT_TYPE = { type: 'object', fields: { total: { type: 'number' } } } as never;
describe('ts-support', () => {
it('expands aliases, enums and interfaces in resolved types', () => {
const resolver = createTypeResolver(tsc);
const resolved = resolver(SOURCE, INPUT_TYPE);
expect(resolved).toContain('"basic" | "premium"');
expect(resolved).toContain('"EU" | "US"');
expect(resolved).toContain('note: string');
expect(resolved).not.toContain('Level');
expect(resolved).not.toContain('Region');
expect(resolved).not.toContain('Extra');
});
it('reports TS diagnostics with prelude-adjusted offsets', () => {
const checker = createFunctionChecker(tsc);
const broken = SOURCE.replace('Level.Basic', 'Level.Missing');
const diagnostics = checker(broken, INPUT_TYPE);
expect(diagnostics.some((d) => d.message.includes("'Missing'"))).toBe(true);
for (const diagnostic of diagnostics) {
expect(diagnostic.start).toBeGreaterThanOrEqual(0);
expect(broken.slice(diagnostic.start, diagnostic.start + diagnostic.length)).toBe('Missing');
}
});
it('auto-resolves function types when passed to Workspace', () => {
const ws = new Workspace(createTypeResolver(tsc));
ws.setDocument('g', {
nodes: [
{
id: 'in1',
type: 'inputNode',
name: 'Request',
content: {
schema: JSON.stringify({
type: 'object',
required: ['total'],
properties: { total: { type: 'number' } },
}),
},
},
{ id: 'fn', type: 'functionNode', name: 'Score', content: { source: SOURCE } },
{ id: 'out1', type: 'outputNode', name: 'Response', content: {} },
],
edges: [
{ id: 'e1', sourceId: 'in1', targetId: 'fn' },
{ id: 'e2', sourceId: 'fn', targetId: 'out1' },
],
});
expect(ws.diagnostics('g')).toEqual([]);
const outputs = ws.outputs({ policyPath: 'g' });
const level = outputs.find((o) => o.path === 'level');
expect(level?.resolvedType).toEqual({ name: null, type: 'enum', values: ['basic', 'premium'] });
});
it('renders variable types as TypeScript', () => {
expect(variableTypeToTs(INPUT_TYPE)).toBe('{ total: number }');
});
});