fbredius/storybook

View on GitHub
app/server/src/lib/compiler/stringifier.ts

Summary

Maintainability
A
3 hrs
Test Coverage
import dedent from 'ts-dedent';
import { StorybookStory, StorybookSection } from './types';

const { identifier } = require('safe-identifier');

export function stringifyObject(object: any, level = 0, excludeOuterParams = false): string {
  if (typeof object === 'string') {
    return JSON.stringify(object);
  }
  const indent = '  '.repeat(level);
  if (Array.isArray(object)) {
    const arrayStrings: string[] = object.map((item: any) => stringifyObject(item, level + 1));
    const arrayString = arrayStrings.join(`,\n${indent}  `);
    if (excludeOuterParams) return arrayString;
    return `[\n${indent}  ${arrayString}\n${indent}]`;
  }
  if (typeof object === 'object') {
    let objectString = '';
    if (Object.keys(object).length > 0) {
      const objectStrings: string[] = Object.keys(object).map((key) => {
        const value: string = stringifyObject(object[key], level + 1);
        return `\n${indent}  ${key}: ${value}`;
      });
      objectString = objectStrings.join(',');
    }
    if (excludeOuterParams) return objectString;
    if (objectString.length === 0) return '{}';
    return `{${objectString}\n${indent}}`;
  }

  return object;
}

export function stringifyImports(imports: Record<string, string[]>): string {
  if (Object.keys(imports).length === 0) return '';
  return Object.entries(imports)
    .map(([module, names]) => `import { ${names.sort().join(', ')} } from '${module}';\n`)
    .join('');
}

export function stringifyDecorators(decorators: string[]): string {
  return decorators && decorators.length > 0
    ? `\n  decorators: [\n    ${decorators.join(',\n    ')}\n  ],`
    : '';
}

export function stringifyDefault(section: StorybookSection): string {
  const { title, imports, decorators, stories, ...options } = section;

  const decoratorsString = stringifyDecorators(decorators);

  const optionsString = stringifyObject(options, 0, true);

  return dedent`
  export default {
    title: ${JSON.stringify(title)},${decoratorsString}${optionsString}
  };
  
  `;
}

export function stringifyStory(story: StorybookStory): string {
  const { name, ...options } = story;
  const storyId = identifier(name);

  const exportedStory = { name, ...options };

  const storyStrings = [`export const ${storyId} = ${stringifyObject(exportedStory)};`, ''];

  return storyStrings.join('\n');
}

export function stringifySection(section: StorybookSection): string {
  const sectionString = [
    stringifyImports(section.imports),
    stringifyDefault(section),
    ...section.stories.map((story) => stringifyStory(story)),
  ].join('\n');

  return sectionString;
}