Skip to content

Commit

Permalink
feat: init add command (#13)
Browse files Browse the repository at this point in the history
* feat: init add command

* fix: judge repair

* fix: add type

* fix: pnpm setup

* fix: update dep

* fix: partial tailwind output

* fix: pnpm setup problem

* fix: output-info type error

* fix: review problem

* fix: add command remove error about add and redundant

* fix: add command warn logger optimize

* fix: remove redundant return command

* fix: optimize logger

* fix: optimize all option tailwind log

* fix: tailwind plugin content error
  • Loading branch information
winchesHe committed Apr 14, 2024
1 parent e548ed8 commit a62919d
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 27 deletions.
72 changes: 54 additions & 18 deletions src/actions/add-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ import {getPackageInfo} from '@helpers/package';
import {findFiles} from '@helpers/utils';
import {nextUIComponents, nextUIComponentsMap} from 'src/constants/component';
import {resolver} from 'src/constants/path';
import {NEXT_UI, individualTailwindRequired, pnpmRequired} from 'src/constants/required';
import {
DOCS_PROVIDER_SETUP,
NEXT_UI,
individualTailwindRequired,
pnpmRequired
} from 'src/constants/required';
import {tailwindTemplate} from 'src/constants/templates';
import {getAutocompleteMultiselect} from 'src/prompts';

Expand All @@ -30,27 +35,36 @@ interface AddActionOptions {
packagePath?: string;
tailwindPath?: string;
appPath?: string;
addApp?: boolean;
}

export async function addAction(components: string[], options: AddActionOptions) {
const {
addApp = false,
all = false,
appPath = findFiles('**/App.(j|t)sx')[0],
packagePath = resolver('package.json'),
prettier = false,
tailwindPath = findFiles('**/tailwind.config.(j|t)s')[0]
} = options;

var {allDependenciesKeys, currentComponents} = getPackageInfo(packagePath);

if (!components.length && !all) {
components = await getAutocompleteMultiselect(
'Select the NextUI components to add',
nextUIComponents.map((component) => {
return {
description: component.description,
title: component.name,
value: component.name
};
})
nextUIComponents
.filter(
(component) =>
!currentComponents.some((currentComponent) => currentComponent.name === component.name)
)
.map((component) => {
return {
description: component.description,
title: component.name,
value: component.name
};
})
);
} else if (all) {
components = [NEXT_UI];
Expand Down Expand Up @@ -79,7 +93,7 @@ export async function addAction(components: string[], options: AddActionOptions)
}

// Check whether the App.tsx file exists
if (!appPath) {
if (addApp && !appPath) {
Logger.prefix(
'error',
"❌ Cannot find the App.(j|t)sx file\nYou should specify appPath through 'add --appPath=yourAppPath'"
Expand Down Expand Up @@ -149,15 +163,17 @@ export async function addAction(components: string[], options: AddActionOptions)
Logger.info(`Added the required tailwind content in file: ${tailwindPath}`);
}

/** ======================== Step 3 Provider ======================== */
const [isCorrectProvider] = checkApp(type, appPath);
/** ======================== Step 3 Provider Need Manually Open ======================== */
if (addApp && appPath && existsSync(appPath)) {
const [isCorrectProvider] = checkApp(type, appPath);

if (!isCorrectProvider) {
fixProvider(appPath, {format: prettier});
if (!isCorrectProvider) {
fixProvider(appPath, {format: prettier});

Logger.newLine();
Logger.info(`Added the NextUIProvider in file: ${appPath}`);
Logger.warn('You need to check the NextUIProvider whether in the correct place');
Logger.newLine();
Logger.info(`Added the NextUIProvider in file: ${appPath}`);
Logger.warn('You need to check the NextUIProvider whether in the correct place');
}
}

/** ======================== Step 4 Setup Pnpm ======================== */
Expand All @@ -177,7 +193,27 @@ export async function addAction(components: string[], options: AddActionOptions)

// Finish adding the NextUI components
Logger.newLine();
Logger.success(
'✅ All the NextUI components have been added\nNow you can use the component you installed in your application'
Logger.success('✅ All the NextUI components have been added\n');

// Warn the user to check the NextUIProvider whether in the correct place
Logger.warn(
`Please check the ${chalk.bold(
'NextUIProvider'
)} whether in the correct place (ignore if added)\nSee more info here: ${DOCS_PROVIDER_SETUP}`
);

// Check whether the user has installed the All NextUI components
if ((allDependenciesKeys.has(NEXT_UI) || all) && currentComponents.length) {
// Check whether have added redundant dependencies
Logger.newLine();
Logger.warn(
'You do not need the `@nextui-org/react` package when using individual components\nWe suggest to use individual components for smaller bundle sizes'
);
Logger.warn('The redundant dependencies are:');
currentComponents.forEach((component) => {
Logger.info(`- ${component.package}`);
});
}

process.exit(0);
}
7 changes: 4 additions & 3 deletions src/constants/required.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ export const DOCS_TAILWINDCSS_SETUP =
'https://nextui.org/docs/guide/installation#tailwind-css-setup';
export const DOCS_APP_SETUP = 'https://nextui.org/docs/guide/installation#provider-setup';
export const DOCS_PNPM_SETUP = 'https://nextui.org/docs/guide/installation#setup-pnpm-optional';
export const DOCS_PROVIDER_SETUP = 'https://nextui.org/docs/guide/installation#provider-setup';

// Record the required content of tailwind.config file
export const tailwindRequired = {
content: '@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}',
content: './node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}',
darkMode: 'darkMode: "class"',
plugins: 'nextui()'
} as const;
Expand All @@ -44,15 +45,15 @@ export const individualTailwindRequired = {
];

if (outputComponents.length === 1) {
return `@nextui-org/theme/dist/components/${currentComponents[0]}.js`;
return `./node_modules/@nextui-org/theme/dist/components/${currentComponents[0]}.js`;
}
const requiredContent = outputComponents
.reduce((acc, component) => {
return (acc += `${component}|`);
}, '')
.replace(/\|$/, '');

return `@nextui-org/theme/dist/components/(${requiredContent}).js`;
return `./node_modules/@nextui-org/theme/dist/components/(${requiredContent}).js`;
},
plugins: 'nextui()'
} as const;
Expand Down
31 changes: 29 additions & 2 deletions src/helpers/fix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,42 @@ export function fixTailwind(type: CheckType, options: FixTailwind) {
}

let tailwindContent = readFileSync(tailwindPath, 'utf-8');
const contentMatch = getMatchArray('content', tailwindContent);
let contentMatch = getMatchArray('content', tailwindContent);
const pluginsMatch = getMatchArray('plugins', tailwindContent);

for (const errorInfo of errorInfoList) {
const [errorType, info] = transformErrorInfo(errorInfo);

if (errorType === 'content') {
// Check if all the required content is added then skip
const allPublic = contentMatch.includes(tailwindRequired.content);

if (allPublic) continue;

contentMatch = contentMatch.filter((content) => !content.includes('@nextui-org/theme/dist/'));
contentMatch.push(info);
tailwindContent = replaceMatchArray('content', tailwindContent, contentMatch);
tailwindContent = replaceMatchArray(
'content',
tailwindContent,
contentMatch,
contentMatch
.map((v, index, arr) => {
// Add 4 spaces before the content
if (index === 0) {
if (arr.length === 1) {
return `\n ${JSON.stringify(v)}\n`;
}

return `\n ${JSON.stringify(v)}`;
}
if (arr.length - 1 === index) {
return ` ${JSON.stringify(v)}\n `;
}

return ` ${JSON.stringify(v)}`;
})
.join(',\n')
);
} else if (errorType === 'plugins') {
pluginsMatch.push(info);
tailwindContent = replaceMatchArray('plugins', tailwindContent, pluginsMatch);
Expand Down
15 changes: 11 additions & 4 deletions src/helpers/match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function getMatchArray(key: string, target: string) {
target
.match(mixinReg)?.[1]
?.split(/,\n/)
.map((i) => i.trim())
.map((i) => i.trim().replace(/[`'"]/g, ''))
.filter(Boolean) ?? []
);

Expand All @@ -51,12 +51,19 @@ export function getMatchArray(key: string, target: string) {
* @param target
* @param value
*/
export function replaceMatchArray(key: string, target: string, value: string[]) {
export function replaceMatchArray(
key: string,
target: string,
value: string[],
_replaceValue?: string
) {
const mixinReg = new RegExp(`\\s*${key}:\\s\\[([\\w\\W]*?)\\]\\s*`);
const replaceValue = value.map((v) => JSON.stringify(v)).join(', ');
const replaceValue = _replaceValue ?? value.map((v) => JSON.stringify(v)).join(', ');

if (mixinReg.test(target)) {
return target.replace(mixinReg, `\n ${key}: [${replaceValue}]`);
const _value = key === 'content' ? `\n ${key}: [${replaceValue}]` : `\n ${key}: [${value}]`;

return target.replace(mixinReg, _value);
}

// If the key does not exist, add the key and value to the end of the target
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ nextui
'Add prettier format in the add content which required installed prettier',
false
)
.option('--addApp [boolean]', 'Add App.tsx file content which required provider', false)
.action(addAction);

nextui
Expand Down

0 comments on commit a62919d

Please sign in to comment.