diff --git a/src/handlers/componentInstall.ts b/src/handlers/componentInstall.ts index 83b8edd..371c254 100644 --- a/src/handlers/componentInstall.ts +++ b/src/handlers/componentInstall.ts @@ -19,7 +19,7 @@ import catchLater from '../util/catchLater'; */ export default async function componentInstall( name: string, - { force, all }: InstallComponentHandlerOptions + { force, all, componentSet }: InstallComponentHandlerOptions ): Promise { const emulsifyConfig = await getEmulsifyConfig(); if (!emulsifyConfig) { @@ -89,10 +89,10 @@ export default async function componentInstall( ); } - if (!name && !all) { + if (!name && !all && !componentSet) { return log( 'error', - 'Please specify a component to install, or pass --all to install all available components.' + 'Please specify a component to install, or library name through option --component-set, or pass --all to install all available components.' ); } @@ -114,11 +114,34 @@ export default async function componentInstall( ]) ); } + // Pull library marked modules. + else if (componentSet) { + const parentComponents = variantConf.components + .filter((component) => component.componentSet?.includes(componentSet)) + .map((component) => component.name); + const componentsWithDependencies = buildComponentDependencyList( + variantConf.components, + parentComponents + ); + componentsWithDependencies.forEach((componentName) => { + components.push([ + componentName, + catchLater( + installComponentFromCache( + systemConf, + variantConf, + componentName, + force + ) + ), + ]); + }); + } // If there is only one component to install, add one single promise for the single component. else { const componentsWithDependencies = buildComponentDependencyList( variantConf.components, - name + [name] ); componentsWithDependencies.forEach((componentName) => { components.push([ diff --git a/src/index.ts b/src/index.ts index 89a3c21..2fc85ed 100644 --- a/src/index.ts +++ b/src/index.ts @@ -90,6 +90,10 @@ component '-a --all', 'Use this to install all available components, rather than specifying a single component to install' ) + .option( + '-cs --component-set ', + 'Use this to Install a pre-defined set of related components from your component library' + ) .alias('i') .description( "Install a component from within the current project's system and variant" diff --git a/src/schemas/variant.json b/src/schemas/variant.json index b03a8c2..21a6d08 100644 --- a/src/schemas/variant.json +++ b/src/schemas/variant.json @@ -56,6 +56,13 @@ "items": { "type": "string" } + }, + "componentSet": { + "type": "array", + "description": "List of all component library to which this component belonning to and should be installed as part of library", + "items": { + "type": "string" + } } }, "additionalProperties": false, diff --git a/src/types/_system.d.ts b/src/types/_system.d.ts index c552076..9e47a59 100644 --- a/src/types/_system.d.ts +++ b/src/types/_system.d.ts @@ -76,6 +76,10 @@ export interface EmulsifySystem { * Array containing list of all components from which depends current conponent */ dependency?: string[]; + /** + * List of all component library to which this component belonning to and should be installed as part of library + */ + componentSet?: string[]; }[]; /** * Array containing objects that define general directories. These directories should contain files and assets that do not belong in a structure folder (such as font files) diff --git a/src/types/_variant.d.ts b/src/types/_variant.d.ts index 3103921..ec48d35 100644 --- a/src/types/_variant.d.ts +++ b/src/types/_variant.d.ts @@ -46,6 +46,10 @@ export type Components = { * Array containing list of all components from which depends current conponent */ dependency?: string[]; + /** + * List of all component library to which this component belonning to and should be installed as part of library + */ + componentSet?: string[]; }[]; /** * Array containing objects that define general directories. These directories should contain files and assets that do not belong in a structure folder (such as font files) diff --git a/src/types/handlers.d.ts b/src/types/handlers.d.ts index d83a6c0..5d866ba 100644 --- a/src/types/handlers.d.ts +++ b/src/types/handlers.d.ts @@ -19,5 +19,6 @@ declare module '@emulsify-cli/handlers' { export type InstallComponentHandlerOptions = { force?: boolean; all?: boolean; + componentSet: string; }; } diff --git a/src/util/project/buildComponentDependencyList.test.ts b/src/util/project/buildComponentDependencyList.test.ts index 37d963a..b5ab8bb 100644 --- a/src/util/project/buildComponentDependencyList.test.ts +++ b/src/util/project/buildComponentDependencyList.test.ts @@ -36,17 +36,17 @@ describe('buildComponentDependencyList', () => { ] as Components; it('Build list of components without dependency', () => { - expect(buildComponentDependencyList(components, 'buttons')).toEqual([ + expect(buildComponentDependencyList(components, ['buttons'])).toEqual([ 'buttons', ]); }); it('Build all components dependency for not existing component', () => { - expect(buildComponentDependencyList(components, 'test')).toEqual([]); + expect(buildComponentDependencyList(components, ['test'])).toEqual([]); }); it('Build all components dependency tree returning flat list without duplicates', () => { - expect(buildComponentDependencyList(components, 'card')).toEqual([ + expect(buildComponentDependencyList(components, ['card'])).toEqual([ 'card', 'images', 'text', @@ -56,11 +56,17 @@ describe('buildComponentDependencyList', () => { }); it('Build all components dependency tree with hierarchical dependency', () => { - expect(buildComponentDependencyList(components, 'menus')).toEqual([ + expect(buildComponentDependencyList(components, ['menus'])).toEqual([ 'menus', 'images', 'text', 'links', ]); }); + + it('Build all components dependency tree for 2 components', () => { + expect(buildComponentDependencyList(components, ['menus', 'card'])).toEqual( + ['menus', 'card', 'images', 'text', 'links', 'buttons'] + ); + }); }); diff --git a/src/util/project/buildComponentDependencyList.ts b/src/util/project/buildComponentDependencyList.ts index 0e775c4..dddf669 100644 --- a/src/util/project/buildComponentDependencyList.ts +++ b/src/util/project/buildComponentDependencyList.ts @@ -2,26 +2,28 @@ import type { Components } from '@emulsify-cli/config'; export default function buildComponentDependencyList( components: Components, - name: string + componentsList: string[] ) { - const rootComponent = components.filter( - (component) => component.name == name + const rootComponents = components.filter((component) => + componentsList.includes(component.name) ); - if (rootComponent.length == 0) return []; - let finalList = [name]; - if (rootComponent.length > 0) { - const list = rootComponent[0].dependency as string[]; - if (list && list.length > 0) { - list.forEach((componentName: string) => { - finalList = [ - ...new Set( - finalList.concat( - buildComponentDependencyList(components, componentName) - ) - ), - ]; - }); - } + if (rootComponents.length == 0) return []; + let finalList = [...componentsList]; + if (rootComponents.length > 0) { + rootComponents.forEach((rootComponent) => { + const list = rootComponent.dependency as string[]; + if (list && list.length > 0) { + list.forEach((componentName: string) => { + finalList = [ + ...new Set( + finalList.concat( + buildComponentDependencyList(components, [componentName]) + ) + ), + ]; + }); + } + }); } return finalList; }