UNPKG

@code-to-json/core

Version:
356 lines (339 loc) 10.2 kB
import { isDefined } from '@code-to-json/utils'; import { expect } from 'chai'; import { describe, it } from 'mocha'; import SingleFileAcceptanceTestCase from './helpers/test-case'; describe('Signature serialization tests', () => { it('function with one signature', async () => { const code = `export function add(a: number, b: number) { return a + b; }`; const t = new SingleFileAcceptanceTestCase(code); await t.run(); const file = t.sourceFile(); const fileSymbol = t.resolveReference(file.symbol); const fnSymbol = t.resolveReference(fileSymbol.exports!.add); expect(fnSymbol.text).to.eql('add'); expect(fnSymbol.flags).to.eql(['Function'], 'Regarded as a function'); const fnType = t.resolveReference(fnSymbol.valueDeclarationType); expect(fnType.text).to.eq('(a: number, b: number) => number'); expect(fnType.callSignatures!.length).to.eq(1); expect(fnType.callSignatures![0].text).to.eq('(a: number, b: number): number'); expect( fnType .callSignatures![0].parameters!.map(p => t.resolveReference(p)) .filter(isDefined) .map(s => ({ name: s.text || s.name, type: t.resolveReference(s.valueDeclarationType).text, })), ).to.deep.eq([ { name: 'a', type: 'number', }, { name: 'b', type: 'number', }, ]); t.cleanup(); }); it('param and return types via JSDoc comment', async () => { const code = `/** * @param a {string} first thing * @param b {string} second thing * @returns {string} concatenated strings */ export function add(a, b) { return a + b; }`; const t = new SingleFileAcceptanceTestCase(code, 'js'); await t.run(); const file = t.sourceFile(); const fileSymbol = t.resolveReference(file.symbol); const fnSymbol = t.resolveReference(fileSymbol.exports!.add); expect(fnSymbol.text).to.eql('add'); expect(fnSymbol.flags).to.eql(['Function'], 'Regarded as a function'); const fnType = t.resolveReference(fnSymbol.valueDeclarationType); expect(fnType.text).to.eq('(a: string, b: string) => string'); expect(fnType.callSignatures!.length).to.eq(1); expect(fnType.callSignatures![0].text).to.eq('(a: string, b: string): string'); expect( fnType .callSignatures![0].parameters!.map(p => t.resolveReference(p)) .filter(isDefined) .map(s => ({ name: s.text || s.name, type: t.resolveReference(s.valueDeclarationType).text, })), ).to.deep.eq([ { name: 'a', type: 'string', }, { name: 'b', type: 'string', }, ]); t.cleanup(); }); it('function with multiple signatures', async () => { const code = `export function add(a: string, b: string): string; export function add(a: number, b: number): number; export function add(a: number | string, b: number | string): number | string { if (typeof a === 'number' && typeof b === 'number') { return a + b; } else if (typeof a === 'string' && typeof b === 'string') { return a + b; } else { throw new Error('unreachable'); } }`; const t = new SingleFileAcceptanceTestCase(code); await t.run(); const file = t.sourceFile(); const fileSymbol = t.resolveReference(file.symbol); const fnSymbol = t.resolveReference(fileSymbol.exports!.add); expect(fnSymbol.text).to.eql('add'); expect(fnSymbol.flags).to.eql(['Function'], 'Regarded as a function'); const fnType = t.resolveReference(fnSymbol.valueDeclarationType); expect(fnType.text).to.eq( '{ (a: string, b: string): string; (a: number, b: number): number; }', ); expect(fnType.callSignatures!.length).to.eq(2); expect(fnType.callSignatures![0].text).to.eq('(a: string, b: string): string'); expect( fnType .callSignatures![0].parameters!.map(p => t.resolveReference(p)) .filter(isDefined) .map(s => ({ name: s.text || s.name, type: t.resolveReference(s.valueDeclarationType).text, })), ).to.deep.eq([ { name: 'a', type: 'string', }, { name: 'b', type: 'string', }, ]); expect(fnType.callSignatures![1].text).to.eq('(a: number, b: number): number'); expect( fnType .callSignatures![1].parameters!.map(p => t.resolveReference(p)) .filter(isDefined) .map(s => ({ name: s.text || s.name, type: t.resolveReference(s.valueDeclarationType).text, })), ).to.deep.eq([ { name: 'a', type: 'number', }, { name: 'b', type: 'number', }, ]); t.cleanup(); }); it('function with multiple signatures, sharing documentation', async () => { const code = ` /** * Add a couple of things together * @param a first * @param b second * * @author Mike */ export function add(a: string, b: string): string; export function add(a: number, b: number): number; export function add(a: number | string, b: number | string): number | string { if (typeof a === 'number' && typeof b === 'number') { return a + b; } else if (typeof a === 'string' && typeof b === 'string') { return a + b; } else { throw new Error('unreachable'); } }`; const t = new SingleFileAcceptanceTestCase(code); await t.run(); const file = t.sourceFile(); const fileSymbol = t.resolveReference(file.symbol); const fnSymbol = t.resolveReference(fileSymbol.exports!.add); expect(fnSymbol.text).to.eql('add'); expect(fnSymbol.flags).to.eql(['Function'], 'Regarded as a function'); expect(fnSymbol.documentation).to.deep.eq({ customTags: [ { content: ['Mike'], kind: 'blockTag', tagName: 'author', }, ], params: [ { content: ['first'], kind: 'param', name: 'a', tagName: 'param', }, { content: ['second'], kind: 'param', name: 'b', tagName: 'param', }, ], summary: ['Add a couple of things together'], }); const fnType = t.resolveReference(fnSymbol.valueDeclarationType); expect(fnType.text).to.eq( '{ (a: string, b: string): string; (a: number, b: number): number; }', ); expect(fnType.callSignatures!.length).to.eq(2); expect(fnType.callSignatures![0].text).to.eq('(a: string, b: string): string'); expect(fnType.callSignatures![0].documentation).to.deep.eq({ customTags: [ { content: ['Mike'], kind: 'blockTag', tagName: 'author', }, ], params: [ { content: ['first'], kind: 'param', name: 'a', tagName: 'param', }, { content: ['second'], kind: 'param', name: 'b', tagName: 'param', }, ], summary: ['Add a couple of things together'], }); expect(fnType.callSignatures![1].documentation).to.eq(undefined); t.cleanup(); }); it('function with multiple signatures, with a doc override for several signatures', async () => { const code = ` /** * Add a couple of strings together * @param a first string * @param b second string * * @author Mike */ export function add(a: string, b: string): string; /** * Add a couple of numbers together * @param a first number * @param b second number * * @author Mike */ export function add(a: number, b: number): number; export function add(a: number | string, b: number | string): number | string { if (typeof a === 'number' && typeof b === 'number') { return a + b; } else if (typeof a === 'string' && typeof b === 'string') { return a + b; } else { throw new Error('unreachable'); } }`; const t = new SingleFileAcceptanceTestCase(code); await t.run(); const file = t.sourceFile(); const fileSymbol = t.resolveReference(file.symbol); const fnSymbol = t.resolveReference(fileSymbol.exports!.add); expect(fnSymbol.text).to.eql('add'); expect(fnSymbol.flags).to.eql(['Function'], 'Regarded as a function'); expect(fnSymbol.documentation).to.deep.eq({ customTags: [ { content: ['Mike'], kind: 'blockTag', tagName: 'author', }, ], params: [ { content: ['first string'], kind: 'param', name: 'a', tagName: 'param', }, { content: ['second string'], kind: 'param', name: 'b', tagName: 'param', }, ], summary: ['Add a couple of strings together'], }); const fnType = t.resolveReference(fnSymbol.valueDeclarationType); expect(fnType.text).to.eq( '{ (a: string, b: string): string; (a: number, b: number): number; }', ); expect(fnType.callSignatures!.length).to.eq(2); expect(fnType.callSignatures![0].text).to.eq('(a: string, b: string): string'); expect(fnType.callSignatures![0].documentation).to.deep.eq({ customTags: [ { content: ['Mike'], kind: 'blockTag', tagName: 'author', }, ], params: [ { content: ['first string'], kind: 'param', name: 'a', tagName: 'param', }, { content: ['second string'], kind: 'param', name: 'b', tagName: 'param', }, ], summary: ['Add a couple of strings together'], }); expect(fnType.callSignatures![1].documentation).to.deep.eq({ customTags: [ { content: ['Mike'], kind: 'blockTag', tagName: 'author', }, ], params: [ { content: ['first number'], kind: 'param', name: 'a', tagName: 'param', }, { content: ['second number'], kind: 'param', name: 'b', tagName: 'param', }, ], summary: ['Add a couple of numbers together'], }); t.cleanup(); }); });