Best JavaScript code snippet using storybook-root
StoryIndexGenerator.ts
Source:StoryIndexGenerator.ts
1import path from 'path';2import fs from 'fs-extra';3import glob from 'globby';4import slash from 'slash';5import type { Path, StoryIndex, V2CompatIndexEntry, StoryId } from '@storybook/store';6import { autoTitleFromSpecifier, sortStoriesV7 } from '@storybook/store';7import type { NormalizedStoriesSpecifier } from '@storybook/core-common';8import { normalizeStoryPath } from '@storybook/core-common';9import { logger } from '@storybook/node-logger';10import { readCsfOrMdx, getStorySortParameter } from '@storybook/csf-tools';11import type { ComponentTitle } from '@storybook/csf';12type SpecifierStoriesCache = Record<Path, StoryIndex['stories'] | false>;13export class StoryIndexGenerator {14 // An internal cache mapping specifiers to a set of path=><set of stories>15 // Later, we'll combine each of these subsets together to form the full index16 private storyIndexEntries: Map<NormalizedStoriesSpecifier, SpecifierStoriesCache>;17 // Cache the last value of `getStoryIndex`. We invalidate (by unsetting) when:18 // - any file changes, including deletions19 // - the preview changes [not yet implemented]20 private lastIndex?: StoryIndex;21 constructor(22 public readonly specifiers: NormalizedStoriesSpecifier[],23 public readonly options: {24 workingDir: Path;25 configDir: Path;26 storiesV2Compatibility: boolean;27 storyStoreV7: boolean;28 }29 ) {30 this.storyIndexEntries = new Map();31 }32 async initialize() {33 // Find all matching paths for each specifier34 await Promise.all(35 this.specifiers.map(async (specifier) => {36 const pathToSubIndex = {} as SpecifierStoriesCache;37 const fullGlob = slash(38 path.join(this.options.workingDir, specifier.directory, specifier.files)39 );40 const files = await glob(fullGlob);41 files.sort().forEach((absolutePath: Path) => {42 const ext = path.extname(absolutePath);43 const relativePath = path.relative(this.options.workingDir, absolutePath);44 if (!['.js', '.jsx', '.ts', '.tsx', '.mdx'].includes(ext)) {45 logger.info(`Skipping ${ext} file ${relativePath}`);46 return;47 }48 pathToSubIndex[absolutePath] = false;49 });50 this.storyIndexEntries.set(specifier, pathToSubIndex);51 })52 );53 // Extract stories for each file54 await this.ensureExtracted();55 }56 async ensureExtracted(): Promise<StoryIndex['stories'][]> {57 return (58 await Promise.all(59 this.specifiers.map(async (specifier) => {60 const entry = this.storyIndexEntries.get(specifier);61 return Promise.all(62 Object.keys(entry).map(63 async (absolutePath) =>64 entry[absolutePath] || this.extractStories(specifier, absolutePath)65 )66 );67 })68 )69 ).flat();70 }71 async extractStories(specifier: NormalizedStoriesSpecifier, absolutePath: Path) {72 const relativePath = path.relative(this.options.workingDir, absolutePath);73 const fileStories = {} as StoryIndex['stories'];74 const entry = this.storyIndexEntries.get(specifier);75 try {76 const importPath = slash(normalizeStoryPath(relativePath));77 const defaultTitle = autoTitleFromSpecifier(importPath, specifier);78 const csf = (await readCsfOrMdx(absolutePath, { defaultTitle })).parse();79 csf.stories.forEach(({ id, name }) => {80 fileStories[id] = {81 id,82 title: csf.meta.title,83 name,84 importPath,85 };86 });87 } catch (err) {88 if (err.name === 'NoMetaError') {89 logger.info(`ð¡ Skipping ${relativePath}: ${err}`);90 } else {91 logger.warn(`ð¨ Extraction error on ${relativePath}: ${err}`);92 throw err;93 }94 }95 entry[absolutePath] = fileStories;96 return fileStories;97 }98 async sortStories(storiesList: StoryIndex['stories'][]) {99 const stories: StoryIndex['stories'] = {};100 storiesList.forEach((subStories) => {101 Object.assign(stories, subStories);102 });103 const sortableStories = Object.values(stories);104 // Skip sorting if we're in v6 mode because we don't have105 // all the info we need here106 if (this.options.storyStoreV7) {107 const storySortParameter = await this.getStorySortParameter();108 const fileNameOrder = this.storyFileNames();109 sortStoriesV7(sortableStories, storySortParameter, fileNameOrder);110 }111 return sortableStories.reduce((acc, item) => {112 acc[item.id] = item;113 return acc;114 }, {} as StoryIndex['stories']);115 }116 async getIndex() {117 if (this.lastIndex) return this.lastIndex;118 // Extract any entries that are currently missing119 // Pull out each file's stories into a list of stories, to be composed and sorted120 const storiesList = await this.ensureExtracted();121 const sorted = await this.sortStories(storiesList);122 let compat = sorted;123 if (this.options.storiesV2Compatibility) {124 const titleToStoryCount = Object.values(sorted).reduce((acc, story) => {125 acc[story.title] = (acc[story.title] || 0) + 1;126 return acc;127 }, {} as Record<ComponentTitle, number>);128 compat = Object.entries(sorted).reduce((acc, entry) => {129 const [id, story] = entry;130 acc[id] = {131 ...story,132 id,133 kind: story.title,134 story: story.name,135 parameters: {136 __id: story.id,137 docsOnly: titleToStoryCount[story.title] === 1 && story.name === 'Page',138 fileName: story.importPath,139 },140 };141 return acc;142 }, {} as Record<StoryId, V2CompatIndexEntry>);143 }144 this.lastIndex = {145 v: 3,146 stories: compat,147 };148 return this.lastIndex;149 }150 invalidate(specifier: NormalizedStoriesSpecifier, importPath: Path, removed: boolean) {151 const absolutePath = slash(path.resolve(this.options.workingDir, importPath));152 const pathToEntries = this.storyIndexEntries.get(specifier);153 if (removed) {154 delete pathToEntries[absolutePath];155 } else {156 pathToEntries[absolutePath] = false;157 }158 this.lastIndex = null;159 }160 async getStorySortParameter() {161 const previewFile = ['js', 'jsx', 'ts', 'tsx']162 .map((ext) => path.join(this.options.configDir, `preview.${ext}`))163 .find((fname) => fs.existsSync(fname));164 let storySortParameter;165 if (previewFile) {166 const previewCode = (await fs.readFile(previewFile, 'utf-8')).toString();167 storySortParameter = await getStorySortParameter(previewCode);168 }169 return storySortParameter;170 }171 // Get the story file names in "imported order"172 storyFileNames() {173 return Array.from(this.storyIndexEntries.values()).flatMap((r) => Object.keys(r));174 }...
Using AI Code Generation
1import { storiesOf } from '@storybook/react';2import { withInfo } from '@storybook/addon-info';3import { withKnobs, text, boolean } from '@storybook/addon-knobs';4import { action } from '@storybook/addon-actions';5import { sortableStories } from 'storybook-root';6const stories = storiesOf('Component', module);7sortableStories(stories);8stories.add('Story 1', withInfo()(() => (9)));10stories.add('Story 2', withInfo()(() => (11)));12stories.add('Story 3', withInfo()(() => (13)));14stories.add('Story 4', withInfo()(() => (15)));16stories.add('Story 5', withInfo()(() => (17)));18stories.add('Story 6', withInfo()(() => (19)));20stories.add('Story 7', withInfo()(() => (21)));22stories.add('Story 8', withInfo()(() => (23)));24stories.add('Story 9', withInfo()(() => (25)));26stories.add('Story 10', withInfo()(() => (27)));28stories.add('Story 11', withInfo()(() => (29)));30stories.add('Story 12', withInfo()(() => (31)));32stories.add('Story 13', withInfo()(() => (33)));34stories.add('Story 14', withInfo()(() => (35)));36stories.add('Story 15', withInfo()(() => (37)));38stories.add('Story 16', withInfo()(() => (39)));40stories.add('Story 17', withInfo()(() => (41)));42stories.add('Story 18', withInfo()(() => (
Using AI Code Generation
1import { sortableStories } from 'storybook-root';2import { storiesOf } from '@storybook/react';3import { withKnobs } from '@storybook/addon-knobs';4import { withInfo } from '@storybook/addon-info';5import { withReadme } from 'storybook-readme';6const stories = sortableStories(storiesOf('MyComponent', module));7 .addDecorator(withKnobs)8 .addDecorator(withInfo)9 .addDecorator(withReadme)10 .add('Story 1', () => <MyComponent />)11 .add('Story 2', () => <MyComponent />)12 .add('Story 3', () => <MyComponent />);13import { isSorted } from 'storybook-root';14export function sortableStories(stories) {15 if (isSorted(stories)) {16 return stories;17 }18 return stories.sort((a, b) => a[0].localeCompare(b[0]));19}20export function isSorted(stories) {21 const keys = Object.keys(stories);22 for (let i = 0; i < keys.length - 1; i += 1) {23 if (keys[i] > keys[i + 1]) {24 return false;25 }26 }27 return true;28}
Using AI Code Generation
1import { sortableStories } from './storybook-root';2import { storiesOf } from './storybook-root';3import { setAddon } from './storybook-root';4import { addDecorator } from './storybook-root';5import { addParameters } from './storybook-root';6import { configure } from './storybook-root';7import { getStorybook } from './storybook-root';8import { raw } from './storybook-root';9import { forceReRender } from './storybook-root';10import { setAddon } from './storybook-root';11import { addDecorator } from './storybook-root';12import { addParameters } from './storybook-root';13import { configure } from './storybook-root';14import { getStorybook } from './storybook-root';15import { raw } from './storybook-root';16import { forceReRender } from './storybook-root';17import { setAddon } from './storybook-root';18import { addDecorator } from './storybook-root';19import { addParameters } from './storybook-root';20import { configure } from './storybook-root';21import { getStorybook } from './storybook-root';22import { raw } from './storybook-root';23import { forceReRender } from './storybook-root';
Using AI Code Generation
1import { sortableStories } from "storybook-root";2export default sortableStories;3import { storiesOf } from "@storybook/react";4export const sortableStories = storiesOf("Sortable", module);5import { sortableStories } from "storybook-root";6import Sortable from "./Sortable";7sortableStories.add("Sortable", () => <Sortable />);8import { sortableStories } from "storybook-root";9import Sortable from "./Sortable";10sortableStories.add("Sortable", () => <Sortable />, { name: "Sortable" });11import { sortableStories } from "storybook-root";12import Sortable from "./Sortable";13sortableStories.add("Sortable", () => <Sortable />, { name: "Sortable" });14import { sortableStories } from "storybook-root";15import Sortable from "./Sortable";16sortableStories.add("Sortable", () => <Sortable />, { name: "Sortable" });17import { sortableStories } from "storybook-root";18import Sortable from "./Sortable";19sortableStories.add("Sortable", () => <Sortable />, { name: "Sortable" });20import { sortableStories } from "storybook-root";21import Sortable from "./Sortable";22sortableStories.add("Sortable", () => <Sortable />, { name: "Sortable" });23import { sortableStories } from "storybook-root";24import Sortable from "./Sortable";25sortableStories.add("Sortable", () => <Sortable />, { name: "Sortable" });26import { sortableStories } from "storybook-root";27import Sortable from "./Sortable";28sortableStories.add("Sortable", () => <Sortable />, { name: "Sortable" });29import { sortableStories } from "storybook-root";30import Sortable from "./Sortable";31sortableStories.add("Sortable", () => <Sortable />, { name: "Sortable" });32import { sortableStories
Using AI Code Generation
1import {sortableStories} from 'storybook-root';2export function sortableStories(stories) {3 return stories.sort((a, b) => {4 if (a[1].name < b[1].name) {5 return -1;6 }7 if (a[1].name > b[1].name) {8 return 1;9 }10 return 0;11 });12}13const {sortableStories} = require('./storybook-root');14module.exports = {15 stories: sortableStories(require.context('../src', true, /\.story\.js$/)),16};
Using AI Code Generation
1import { sortableStories } from 'storybook-root';2const stories = sortableStories(require.context('../src', true, /\.stories\.js$/), 'stories');3stories.forEach(story => {4 story();5});6import { configure } from '@storybook/react';7import { setOptions } from '@storybook/addon-options';8import { setDefaults } from 'storybook-root';9setOptions({10});11setDefaults({12});13configure(() => require('../test'), module);
Using AI Code Generation
1import { sortableStories } from 'storybook-root';2export default {3};4export const NoOrder = () => sortableStories('NoOrder');5export const InOrder = () => sortableStories('InOrder');6export const OutOfOrder = () => sortableStories('OutOfOrder');7export const WithNumbers = () => sortableStories('WithNumbers');8export const WithNumbersAndText = () => sortableStories('WithNumbersAndText');9export const WithNumbersAndTextAndSpecialCharacters = () =>10 sortableStories('WithNumbersAndTextAndSpecialCharacters');11export const WithNumbersAndTextAndSpecialCharactersAndSpaces = () =>12 sortableStories('WithNumbersAndTextAndSpecialCharactersAndSpaces');13export const WithNumbersAndTextAndSpecialCharactersAndSpacesAndUnderscores = () =>14 sortableStories(15 );16export const WithNumbersAndTextAndSpecialCharactersAndSpacesAndUnderscoresAndDashes = () =>17 sortableStories(18 );19export const WithNumbersAndTextAndSpecialCharactersAndSpacesAndUnderscoresAndDashesAndParentheses = () =>20 sortableStories(21 );22export const WithNumbersAndTextAndSpecialCharactersAndSpacesAndUnderscoresAndDashesAndParenthesesAndBrackets = () =>23 sortableStories(24 );25export const WithNumbersAndTextAndSpecialCharactersAndSpacesAndUnderscoresAndDashesAndParenthesesAndBracketsAndBraces = () =>26 sortableStories(27 );28export const WithNumbersAndTextAndSpecialCharactersAndSpacesAndUnderscoresAndDashesAndParenthesesAndBracketsAndBracesAndSlashes = () =>29 sortableStories(30 );
Using AI Code Generation
1import {sortableStories} from 'storybook-root';2import * as stories from 'storybook-root';3import * as stories from 'storybook-root';4import {sortableStories} from 'storybook-root';5import * as stories from 'storybook-root';6import * as stories from 'storybook-root';7import {sortableStories} from 'storybook-root';8import * as stories from 'storybook-root';9import * as stories from 'storybook-root';10import {sortableStories} from 'storybook-root';11import * as stories from 'storybook-root';12import * as stories from 'storybook-root';
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!