@baseplate-dev/core-generators
Version:
Core generators for Baseplate
125 lines • 3.96 kB
JavaScript
/**
* Vitest snapshot serializer for TsCodeFragment
*
* Produces readable snapshots that look like actual TypeScript code output.
*
* @example
* ```typescript
* // In test setup file
* import { extendFragmentSerializer } from '@baseplate-dev/core-generators/test-helpers';
*
* extendFragmentSerializer();
*
* // In tests
* expect(fragment).toMatchSnapshot();
* ```
*
* @packageDocumentation
*/
import { expect } from 'vitest';
import { normalizeFragment } from './utils.js';
/**
* Type guard to detect TsCodeFragment objects
*/
function isTsCodeFragment(val) {
return (val !== null &&
typeof val === 'object' &&
'contents' in val &&
typeof val.contents === 'string');
}
/**
* Formats a single import declaration as a TypeScript import statement
*/
function formatImportStatement(imp) {
const parts = [];
if (imp.namespaceImport) {
parts.push(`* as ${imp.namespaceImport}`);
}
if (imp.defaultImport) {
parts.push(imp.defaultImport);
}
if (imp.namedImports && imp.namedImports.length > 0) {
const namedStr = imp.namedImports
.map((ni) => {
const name = ni.alias ? `${ni.name} as ${ni.alias}` : ni.name;
return ni.isTypeOnly ? `type ${name}` : name;
})
.join(', ');
parts.push(`{ ${namedStr} }`);
}
const importKeyword = imp.isTypeOnly ? 'import type' : 'import';
return `${importKeyword} ${parts.join(', ')} from '${imp.moduleSpecifier}';`;
}
/**
* Indents all lines in a string
*/
function indentLines(text, indent) {
return text
.split('\n')
.map((line) => (line ? `${indent}${line}` : line))
.join('\n');
}
/**
* Serializes a TsCodeFragment to TypeScript-like output
*/
function serializeFragment(fragment, baseIndent, indentUnit) {
const normalized = normalizeFragment(fragment);
const lines = [];
// Hoisted fragments (if present) - each as "Hoisted [key]:"
if (normalized.hoistedFragments && normalized.hoistedFragments.length > 0) {
for (const frag of normalized.hoistedFragments) {
lines.push(`${baseIndent}Hoisted [${frag.key}]:`);
// Recursively serialize the hoisted fragment
const nestedOutput = serializeFragment(frag, baseIndent + indentUnit, indentUnit);
lines.push(nestedOutput, ''); // blank line between hoisted fragments
}
}
// Import statements (if present)
if (normalized.imports && normalized.imports.length > 0) {
for (const imp of normalized.imports) {
lines.push(`${baseIndent}${formatImportStatement(imp)}`);
}
lines.push(''); // blank line after imports
}
// Fragment contents
lines.push(indentLines(normalized.contents, baseIndent));
return lines.join('\n');
}
/**
* Vitest snapshot serializer for TsCodeFragment
*
* Produces TypeScript-like snapshots showing:
* - Hoisted fragments (if any) as nested TsCodeFragment blocks
* - Import statements as actual TypeScript import syntax
* - Fragment contents as code
*/
export const tsFragmentSerializer = {
/**
* Tests if the value is a TsCodeFragment
*/
test(val) {
return isTsCodeFragment(val);
},
/**
* Serializes a TsCodeFragment to a readable string format
*/
serialize(val, config, indentation) {
return serializeFragment(val, indentation, config.indent);
},
};
/**
* Extends Vitest with the TsCodeFragment snapshot serializer
* Call this function once in your test setup to enable the serializer
*
* @example
* ```typescript
* // In test setup file or at the top of test file
* import { extendFragmentSerializer } from '@baseplate-dev/core-generators/test-helpers';
*
* extendFragmentSerializer();
* ```
*/
export function extendFragmentSerializer() {
expect.addSnapshotSerializer(tsFragmentSerializer);
}
//# sourceMappingURL=snapshot-serializer.js.map