mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-08 01:41:49 +08:00
feat: support version matcher functions for framework detection
This commit is contained in:
parent
499de3f465
commit
231b03aa9a
@ -315,6 +315,27 @@ describe('Detect', () => {
|
||||
expect(result).toBe(ProjectType.UNDETECTED);
|
||||
});
|
||||
|
||||
// TODO(blaine): Remove once Vue3 is supported
|
||||
it(`UNDETECTED for Vue framework above version 3.0.0`, () => {
|
||||
const result = detectFrameworkPreset({
|
||||
dependencies: {
|
||||
vue: '3.0.0',
|
||||
},
|
||||
});
|
||||
expect(result).toBe(ProjectType.UNDETECTED);
|
||||
});
|
||||
|
||||
// TODO(blaine): Remove once Nuxt3 is supported
|
||||
it(`UNDETECTED for Nuxt framework above version 3.0.0`, () => {
|
||||
const result = detectFrameworkPreset({
|
||||
dependencies: {
|
||||
nuxt: '3.0.0',
|
||||
},
|
||||
});
|
||||
expect(result).toBe(ProjectType.UNDETECTED);
|
||||
});
|
||||
|
||||
// TODO: The mocking in this test causes tests after it to fail
|
||||
it('REACT_SCRIPTS for custom react scripts config', () => {
|
||||
const forkedReactScriptsConfig = {
|
||||
'/node_modules/.bin/react-scripts': 'file content',
|
||||
|
@ -12,14 +12,32 @@ import {
|
||||
import { getBowerJson } from './helpers';
|
||||
import { PackageJson, readPackageJson } from './js-package-manager';
|
||||
|
||||
const hasDependency = (packageJson: PackageJson, name: string) => {
|
||||
return !!packageJson.dependencies?.[name] || !!packageJson.devDependencies?.[name];
|
||||
const hasDependency = (
|
||||
packageJson: PackageJson,
|
||||
name: string,
|
||||
matcher?: (version: string) => boolean
|
||||
) => {
|
||||
const version = packageJson.dependencies?.[name] || packageJson.devDependencies?.[name];
|
||||
if (version && typeof matcher === 'function') {
|
||||
return matcher(version);
|
||||
}
|
||||
return !!version;
|
||||
};
|
||||
|
||||
const hasPeerDependency = (packageJson: PackageJson, name: string) => {
|
||||
return !!packageJson.peerDependencies?.[name];
|
||||
const hasPeerDependency = (
|
||||
packageJson: PackageJson,
|
||||
name: string,
|
||||
matcher?: (version: string) => boolean
|
||||
) => {
|
||||
const version = packageJson.peerDependencies?.[name];
|
||||
if (version && typeof matcher === 'function') {
|
||||
return matcher(version);
|
||||
}
|
||||
return !!version;
|
||||
};
|
||||
|
||||
type SearchTuple = [string, (version: string) => boolean | undefined];
|
||||
|
||||
const getFrameworkPreset = (
|
||||
packageJson: PackageJson,
|
||||
framework: TemplateConfiguration
|
||||
@ -32,12 +50,32 @@ const getFrameworkPreset = (
|
||||
|
||||
const { preset, files, dependencies, peerDependencies, matcherFunction } = framework;
|
||||
|
||||
if (Array.isArray(dependencies) && dependencies.length > 0) {
|
||||
matcher.dependencies = dependencies.map((name) => hasDependency(packageJson, name));
|
||||
let dependencySearches = [] as SearchTuple[];
|
||||
if (Array.isArray(dependencies)) {
|
||||
dependencySearches = dependencies.map((name) => [name, undefined]);
|
||||
} else if (typeof dependencies === 'object') {
|
||||
dependencySearches = Object.entries(dependencies);
|
||||
}
|
||||
|
||||
if (Array.isArray(peerDependencies) && peerDependencies.length > 0) {
|
||||
matcher.peerDependencies = peerDependencies.map((name) => hasPeerDependency(packageJson, name));
|
||||
// Must check the length so the `[false]` isn't overwritten if `{ dependencies: [] }`
|
||||
if (dependencySearches.length > 0) {
|
||||
matcher.dependencies = dependencySearches.map(([name, matchFn]) =>
|
||||
hasDependency(packageJson, name, matchFn)
|
||||
);
|
||||
}
|
||||
|
||||
let peerDependencySearches = [] as SearchTuple[];
|
||||
if (Array.isArray(peerDependencies)) {
|
||||
peerDependencySearches = peerDependencies.map((name) => [name, undefined]);
|
||||
} else if (typeof peerDependencies === 'object') {
|
||||
peerDependencySearches = Object.entries(peerDependencies);
|
||||
}
|
||||
|
||||
// Must check the length so the `[false]` isn't overwritten if `{ peerDependencies: [] }`
|
||||
if (peerDependencySearches.length > 0) {
|
||||
matcher.peerDependencies = peerDependencySearches.map(([name, matchFn]) =>
|
||||
hasPeerDependency(packageJson, name, matchFn)
|
||||
);
|
||||
}
|
||||
|
||||
if (Array.isArray(files) && files.length > 0) {
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { lt } from '@storybook/semver';
|
||||
|
||||
// Should match @storybook/<framework>
|
||||
export type SupportedFrameworks =
|
||||
| 'react'
|
||||
@ -82,8 +84,8 @@ export type TemplateMatcher = {
|
||||
export type TemplateConfiguration = {
|
||||
preset: ProjectType;
|
||||
/** will be checked both against dependencies and devDependencies */
|
||||
dependencies?: string[];
|
||||
peerDependencies?: string[];
|
||||
dependencies?: string[] | { [dependency: string]: (version: string) => boolean };
|
||||
peerDependencies?: string[] | { [dependency: string]: (version: string) => boolean };
|
||||
files?: string[];
|
||||
matcherFunction: (matcher: TemplateMatcher) => boolean;
|
||||
};
|
||||
@ -112,7 +114,12 @@ export const supportedTemplates: TemplateConfiguration[] = [
|
||||
},
|
||||
{
|
||||
preset: ProjectType.VUE,
|
||||
dependencies: ['vue', 'nuxt'],
|
||||
// The Vue template only works with Vue or Nuxt under v3
|
||||
// In a future update, a new Vue3 template will be added
|
||||
dependencies: {
|
||||
vue: (version) => lt(version, '3.0.0'),
|
||||
nuxt: (version) => lt(version, '3.0.0'),
|
||||
},
|
||||
matcherFunction: ({ dependencies }) => {
|
||||
return dependencies.some(Boolean);
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user