Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Controls: Add Channels API to search for files in the project root #26726

Merged
merged 42 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3a35428
Implement draft version of the file search
valentinpalkovic Apr 2, 2024
5199da5
Add test files
valentinpalkovic Apr 2, 2024
df6e16c
Remove node_modules from gitignore
valentinpalkovic Apr 2, 2024
d0a68b2
Add normalize-path helper util
valentinpalkovic Apr 3, 2024
abeaac6
Adjust test files in controls
valentinpalkovic Apr 3, 2024
f0eec0a
Finalized filesearch in controls
valentinpalkovic Apr 3, 2024
b696c78
Finalized parser API
valentinpalkovic Apr 3, 2024
4aaa5b6
Add isNotNull function to ts-utils.ts
valentinpalkovic Apr 3, 2024
48f0f3b
API Doc: Add fallback for renderer name if not set
valentinpalkovic Apr 3, 2024
efec0b5
Extract util to extract proper framework name
valentinpalkovic Apr 3, 2024
6654fd6
Extract utils and types into @storybook/core-common and @storybook/types
valentinpalkovic Apr 3, 2024
e86e004
Add new function extractProperRendererNameFromFramework
valentinpalkovic Apr 3, 2024
0ee1d50
Implement file-search channel
valentinpalkovic Apr 3, 2024
492a43b
Adjust globbification of search query
valentinpalkovic Apr 3, 2024
272c3d5
Add dependencies and remove unused dependency in package.json and yar…
valentinpalkovic Apr 3, 2024
7e79e80
Improve glob search pattern for file search
valentinpalkovic Apr 3, 2024
3ae848c
Update yarn install command to exclude immutable flag
valentinpalkovic Apr 3, 2024
75b4873
Update yarn.lock
valentinpalkovic Apr 3, 2024
871699e
import globby dynamically because it is a pure ESM module
valentinpalkovic Apr 4, 2024
ca39719
Bump esmodule-lexer
valentinpalkovic Apr 4, 2024
a1305c3
Only search for specific file extensions
valentinpalkovic Apr 4, 2024
7431a0e
Ignore test files in filesearch
valentinpalkovic Apr 4, 2024
7095732
Fix tests
valentinpalkovic Apr 4, 2024
e4a49f8
Fix test
valentinpalkovic Apr 4, 2024
061dbf9
Return null for files which cannot be parsed
valentinpalkovic Apr 4, 2024
e79979b
Add .eslintignore changes and exclude __tests__ directory
valentinpalkovic Apr 4, 2024
8adf047
Increase timeout in test
valentinpalkovic Apr 4, 2024
d015419
Apply requested changes
valentinpalkovic Apr 8, 2024
7fec522
Only eslintignore specific __tests__ directory
valentinpalkovic Apr 8, 2024
e36a1c0
Fix eslintignore pattern
valentinpalkovic Apr 8, 2024
9264728
Fix loading of experimental channel for essential addons
valentinpalkovic Apr 8, 2024
8cbb7fa
Fix server channel registration
valentinpalkovic Apr 8, 2024
58c9c78
Cleanup
valentinpalkovic Apr 8, 2024
23fce6f
Fix normalization on windows
valentinpalkovic Apr 9, 2024
7b6e966
Move code to core-server
valentinpalkovic Apr 9, 2024
e67928a
Adjust gitignore
valentinpalkovic Apr 9, 2024
7f5b3b6
Fix tests and finalize
valentinpalkovic Apr 9, 2024
314112a
Adjust eslintignore
valentinpalkovic Apr 9, 2024
81ce3d4
Update manager global exports
valentinpalkovic Apr 9, 2024
423d404
Remove leftovers
valentinpalkovic Apr 9, 2024
b2d3149
Update lock file
valentinpalkovic Apr 9, 2024
4d055fb
Update exports
valentinpalkovic Apr 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ jobs:
at: .
- run:
name: Install dependencies
command: yarn install
command: yarn install --no-immutable
working_directory: test-storybooks/portable-stories-kitchen-sink/<< parameters.directory >>
- run:
name: Run Jest tests
Expand Down
3 changes: 2 additions & 1 deletion code/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ ember-output
!.eslintrc.js
!.eslintrc-markdown.js
!.storybook
lib/core-common/templates/base-preview-head.html
lib/core-common/templates/base-preview-head.html
lib/core-server/src/utils/__search-files-tests__
7 changes: 2 additions & 5 deletions code/lib/cli/src/automigrate/helpers/mainConfigFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
rendererPackages,
frameworkPackages,
builderPackages,
extractProperFrameworkName,
} from '@storybook/core-common';
import type { StorybookConfigRaw, StorybookConfig } from '@storybook/types';
import type { ConfigFile } from '@storybook/csf-tools';
Expand All @@ -30,11 +31,7 @@ export const getFrameworkPackageName = (mainConfig?: StorybookConfigRaw) => {
return null;
}

const normalizedPath = path.normalize(packageNameOrPath).replace(new RegExp(/\\/, 'g'), '/');

return (
Object.keys(frameworkPackages).find((pkg) => normalizedPath.endsWith(pkg)) || packageNameOrPath
);
return extractProperFrameworkName(packageNameOrPath);
};

/**
Expand Down
50 changes: 10 additions & 40 deletions code/lib/cli/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import stripJsonComments from 'strip-json-comments';
import findUp from 'find-up';
import invariant from 'tiny-invariant';
import { getCliDir, getRendererDir } from './dirs';
import type {
JsPackageManager,
PackageJson,
PackageJsonWithDepsAndDevDeps,
import {
type JsPackageManager,
type PackageJson,
type PackageJsonWithDepsAndDevDeps,
frameworkToRenderer as CoreFrameworkToRenderer,
} from '@storybook/core-common';
import type { SupportedFrameworks } from '@storybook/types';
import type { SupportedRenderers } from './project_types';
import type { SupportedFrameworks, SupportedRenderers } from '@storybook/types';
import { CoreBuilder } from './project_types';
import { SupportedLanguage } from './project_types';
import { versions as storybookMonorepoPackages } from '@storybook/core-common';
Expand Down Expand Up @@ -132,40 +132,10 @@ type CopyTemplateFilesOptions = {
destination?: string;
};

export const frameworkToRenderer: Record<
SupportedFrameworks | SupportedRenderers,
SupportedRenderers | 'vue'
> = {
// frameworks
angular: 'angular',
ember: 'ember',
'html-vite': 'html',
'html-webpack5': 'html',
nextjs: 'react',
'preact-vite': 'preact',
'preact-webpack5': 'preact',
qwik: 'qwik',
'react-vite': 'react',
'react-webpack5': 'react',
'server-webpack5': 'server',
solid: 'solid',
'svelte-vite': 'svelte',
'svelte-webpack5': 'svelte',
sveltekit: 'svelte',
'vue3-vite': 'vue3',
'vue3-webpack5': 'vue3',
'web-components-vite': 'web-components',
'web-components-webpack5': 'web-components',
// renderers
html: 'html',
preact: 'preact',
'react-native': 'react-native',
react: 'react',
server: 'server',
svelte: 'svelte',
vue3: 'vue3',
'web-components': 'web-components',
};
/**
* @deprecated Please use `frameworkToRenderer` from `@storybook/core-common` instead
*/
export const frameworkToRenderer = CoreFrameworkToRenderer;

export const frameworkToDefaultBuilder: Record<SupportedFrameworks, CoreBuilder> = {
angular: CoreBuilder.Webpack5,
Expand Down
23 changes: 8 additions & 15 deletions code/lib/cli/src/project_types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { minVersion, validRange } from 'semver';
import type { SupportedFrameworks } from '@storybook/types';
import type {
SupportedFrameworks,
SupportedRenderers as CoreSupportedFrameworks,
} from '@storybook/types';

function eqMajor(versionRange: string, major: number) {
// Uses validRange to avoid a throw from minVersion if an invalid range gets passed
Expand All @@ -22,20 +25,10 @@ export const externalFrameworks: ExternalFramework[] = [
{ name: 'solid', frameworks: ['storybook-solidjs-vite'], renderer: 'storybook-solidjs' },
];

// Should match @storybook/<renderer>
export type SupportedRenderers =
| 'react'
| 'react-native'
| 'vue3'
| 'angular'
| 'ember'
| 'preact'
| 'svelte'
| 'qwik'
| 'html'
| 'web-components'
| 'server'
| 'solid';
/**
* @deprecated Please use `SupportedFrameworks` from `@storybook/types` instead
*/
export type SupportedRenderers = CoreSupportedFrameworks;

export const SUPPORTED_RENDERERS: SupportedRenderers[] = [
'react',
Expand Down
1 change: 1 addition & 0 deletions code/lib/core-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from './utils/cli';
export * from './utils/check-addon-order';
export * from './utils/envs';
export * from './utils/common-glob-options';
export * from './utils/framework-to-renderer';
export * from './utils/get-builder-options';
export * from './utils/get-framework-name';
export * from './utils/get-renderer-name';
Expand Down
36 changes: 36 additions & 0 deletions code/lib/core-common/src/utils/framework-to-renderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { SupportedFrameworks, SupportedRenderers } from '@storybook/types';

export const frameworkToRenderer: Record<
SupportedFrameworks | SupportedRenderers,
SupportedRenderers | 'vue'
> = {
// frameworks
angular: 'angular',
ember: 'ember',
'html-vite': 'html',
'html-webpack5': 'html',
nextjs: 'react',
'preact-vite': 'preact',
'preact-webpack5': 'preact',
qwik: 'qwik',
'react-vite': 'react',
'react-webpack5': 'react',
'server-webpack5': 'server',
solid: 'solid',
'svelte-vite': 'svelte',
'svelte-webpack5': 'svelte',
sveltekit: 'svelte',
'vue3-vite': 'vue3',
'vue3-webpack5': 'vue3',
'web-components-vite': 'web-components',
'web-components-webpack5': 'web-components',
// renderers
html: 'html',
preact: 'preact',
'react-native': 'react-native',
react: 'react',
server: 'server',
svelte: 'svelte',
vue3: 'vue3',
'web-components': 'web-components',
};
18 changes: 18 additions & 0 deletions code/lib/core-common/src/utils/get-framework-name.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { describe, expect, it } from 'vitest';
import { extractProperFrameworkName } from './get-framework-name';

describe('get-framework-name', () => {
describe('extractProperFrameworkName', () => {
it('should extract the proper framework name from the given framework field', () => {
expect(extractProperFrameworkName('@storybook/angular')).toBe('@storybook/angular');
expect(extractProperFrameworkName('/path/to/@storybook/angular')).toBe('@storybook/angular');
expect(extractProperFrameworkName('\\path\\to\\@storybook\\angular')).toBe(
'@storybook/angular'
);
});

it('should return the given framework name if it is a third-party framework', () => {
expect(extractProperFrameworkName('@third-party/framework')).toBe('@third-party/framework');
});
});
});
16 changes: 16 additions & 0 deletions code/lib/core-common/src/utils/get-framework-name.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { dedent } from 'ts-dedent';
import type { Options } from '@storybook/types';
import { frameworkPackages } from './get-storybook-info';
import { normalizePath } from './normalize-path';

/**
* Framework can be a string or an object. This utility always returns the string name.
Expand All @@ -17,3 +19,17 @@ export async function getFrameworkName(options: Options) {

return typeof framework === 'object' ? framework.name : framework;
}

/**
* Extracts the proper framework name from the given framework field.
* The framework field can be the framework package name or a path to the framework package.
* @example
* extractProperFrameworkName('/path/to/@storybook/angular') // => '@storybook/angular'
* extractProperFrameworkName('@third-party/framework') // => '@third-party/framework'
*/
export const extractProperFrameworkName = (framework: string) => {
const normalizedPath = normalizePath(framework);
const frameworkName = Object.keys(frameworkPackages).find((pkg) => normalizedPath.endsWith(pkg));

return frameworkName ?? framework;
};
17 changes: 17 additions & 0 deletions code/lib/core-common/src/utils/get-renderer-name.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { it } from 'node:test';
import { describe, expect } from 'vitest';
import { extractProperRendererNameFromFramework } from './get-renderer-name';

describe('get-renderer-name', () => {
describe('extractProperRendererNameFromFramework', () => {
it('should return the renderer name for a known framework', async () => {
const renderer = await extractProperRendererNameFromFramework('@storybook/react');
expect(renderer).toEqual('react');
});

it('should return null for an unknown framework', async () => {
const renderer = await extractProperRendererNameFromFramework('@third-party/framework');
expect(renderer).toBeNull();
});
});
});
25 changes: 24 additions & 1 deletion code/lib/core-common/src/utils/get-renderer-name.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type { Options } from '@storybook/types';
import { getFrameworkName } from './get-framework-name';
import { extractProperFrameworkName, getFrameworkName } from './get-framework-name';
import { frameworkPackages } from './get-storybook-info';
import { frameworkToRenderer } from './framework-to-renderer';

/**
* Render is set as a string on core. It must be set by the framework
* It falls back to the framework name if not set
*/
export async function getRendererName(options: Options) {
const core = await options.presets.apply('core', {}, options);
Expand All @@ -15,3 +18,23 @@ export async function getRendererName(options: Options) {

return core.renderer;
}

/**
* Extracts the proper renderer name from the given framework name.
* @param frameworkName The name of the framework.
* @returns The name of the renderer.
* @example
* extractProperRendererNameFromFramework('@storybook/react') // => 'react'
* extractProperRendererNameFromFramework('@storybook/angular') // => 'angular'
* extractProperRendererNameFromFramework('@third-party/framework') // => null
*/
export async function extractProperRendererNameFromFramework(frameworkName: string) {
const extractedFrameworkName = extractProperFrameworkName(frameworkName);
const framework = frameworkPackages[extractedFrameworkName];

if (!framework) {
return null;
}

return frameworkToRenderer[framework as keyof typeof frameworkToRenderer];
}
11 changes: 11 additions & 0 deletions code/lib/core-common/src/utils/normalize-path.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { normalizePath } from './normalize-path';
import { describe, expect, it } from 'vitest';

describe('normalize-path', () => {
it('should normalize paths', () => {
expect(normalizePath('path/to/../file')).toBe('path/file');
expect(normalizePath('path/to/./file')).toBe('path/to/file');
expect(normalizePath('path\\to\\file')).toBe('path/to/file');
expect(normalizePath('foo\\..\\bar')).toBe('bar');
});
});
14 changes: 14 additions & 0 deletions code/lib/core-common/src/utils/normalize-path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import path from 'path';

/**
* Normalize a path to use forward slashes and remove .. and .
* @param p The path to normalize
* @returns The normalized path
* @example
* normalizePath('path/to/../file') // => 'path/file'
* normalizePath('path/to/./file') // => 'path/to/file'
* normalizePath('path\\to\\file') // => 'path/to/file'
*/
export function normalizePath(p: string) {
return path.posix.normalize(p.replace(/\\/g, '/'));
}
4 changes: 4 additions & 0 deletions code/lib/core-events/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ enum events {
SET_WHATS_NEW_CACHE = 'setWhatsNewCache',
TOGGLE_WHATS_NEW_NOTIFICATIONS = 'toggleWhatsNewNotifications',
TELEMETRY_ERROR = 'telemetryError',
FILE_COMPONENT_SEARCH = 'fileComponentSearch',
FILE_COMPONENT_SEARCH_RESULT = 'fileComponentSearchResult',
}

// Enables: `import Events from ...`
Expand All @@ -87,6 +89,8 @@ export const {
CURRENT_STORY_WAS_SET,
DOCS_PREPARED,
DOCS_RENDERED,
FILE_COMPONENT_SEARCH,
FILE_COMPONENT_SEARCH_RESULT,
FORCE_RE_RENDER,
FORCE_REMOUNT,
GLOBALS_UPDATED,
Expand Down
2 changes: 2 additions & 0 deletions code/lib/core-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,11 @@
"@types/semver": "^7.3.4",
"better-opn": "^3.0.2",
"chalk": "^4.1.0",
"cjs-module-lexer": "^1.2.3",
"cli-table3": "^0.6.1",
"compression": "^1.7.4",
"detect-port": "^1.3.0",
"es-module-lexer": "^1.5.0",
"express": "^4.17.3",
"fs-extra": "^11.1.0",
"globby": "^14.0.1",
Expand Down
3 changes: 3 additions & 0 deletions code/lib/core-server/src/presets/common-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import invariant from 'tiny-invariant';
import { parseStaticDir } from '../utils/server-statics';
import { defaultStaticDirs } from '../utils/constants';
import { sendTelemetryError } from '../withTelemetry';
import { initFileSearchChannel } from '../server-channel/file-search-channel';

const interpolate = (string: string, data: Record<string, string> = {}) =>
Object.entries(data).reduce((acc, [k, v]) => acc.replace(new RegExp(`%${k}%`, 'g'), v), string);
Expand Down Expand Up @@ -340,6 +341,8 @@ export const experimental_serverChannel = async (
}
});

initFileSearchChannel(channel, options);

return channel;
};

Expand Down
Loading