Skip to content

Commit 1c68ded

Browse files
authored
feat: Preserve CSS & Package Manager (#34)
* feat: Preserve CSS & Package Manager * Version patch
1 parent e141e00 commit 1c68ded

12 files changed

+115
-22
lines changed

README.md

+25-1
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,36 @@ Here is a screen grab of how it looks.
1515

1616
## :gift: Installation
1717

18-
Scaffold a new project of your choice then simply run,
18+
Scaffold a new project of your choice of framework, then simply run,
1919

2020
```sh
2121
npx twify init
2222
```
2323

24+
### Command Options
25+
26+
Other than `--help` you can also do more.
27+
28+
#### Preserve Existing CSS
29+
30+
By default, twify will replace your existing CSS and only keep Tailwind. But if you want to preserve the existing CSS you can use the `-p, --preserve` flag.
31+
32+
```sh
33+
npx twify init -p
34+
# OR
35+
npx twify init --preserve
36+
```
37+
38+
#### Force Package Manager for Installation
39+
40+
By default, twify will try to guess the Package Manager for installing dependencies in your project but if you want to force your standard or you don't want to take any chances you can use the `-i, --installer` option.
41+
42+
```sh
43+
npx twify init -i yarn # Options: npm, yarn, pnpm
44+
# OR
45+
npx twify init --installer yarn
46+
```
47+
2448
## :star: Supported Projects
2549

2650
Below are the list of Supported Projects,

assets/twify.png

-724 KB
Loading

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "twify",
3-
"version": "0.3.0",
3+
"version": "0.3.1",
44
"description": "A Tool to Setup TailwindCSS in your Project with a Single Command",
55
"bin": {
66
"twify": "dist/main.js"

src/commands/init.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import gradient from 'gradient-string';
44
import { drivers } from '../drivers';
55
import { detectFramework } from '../helpers';
66
import { handle } from '../processor';
7+
import { InitOptions } from '../types';
78

8-
export const InitCommand = async () => {
9+
export const InitCommand = async (options: InitOptions = {}) => {
910
console.log(gradient.fruit('\n\n🔥 Welcome to Twify!\n'));
1011
console.log(
1112
chalk.blue.bold(
@@ -65,7 +66,7 @@ export const InitCommand = async () => {
6566

6667
console.log(chalk.cyan.bold('\n🚀 Applying fresh quote of paint...'));
6768
try {
68-
await handle(framework);
69+
await handle(framework, options);
6970

7071
console.log(gradient.morning('\n✨ You are all set with TailwindCSS! \n'));
7172
} catch (e) {

src/helpers.ts

+16-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from 'fs-extra';
22
import { exec } from 'child_process';
33
import path from 'path';
4-
import { Driver } from './types';
4+
import { Driver, PackageManager } from './types';
55
import { dirname, join } from 'path';
66
import { fileURLToPath } from 'url';
77

@@ -28,10 +28,21 @@ export function detectFramework(): Driver | undefined {
2828
if (devDependencies['vite']) return 'Vite';
2929
}
3030

31-
export function detectInstaller(): string {
32-
return fs.existsSync(path.join(process.cwd(), 'yarn.lock'))
33-
? 'yarn add --dev'
34-
: 'npm install --save-dev';
31+
export function installerPrefix(manager?: PackageManager): string {
32+
const npm = 'npm install --save-dev';
33+
const yarn = 'yarn add --dev';
34+
const pnpm = 'pnpm install --save-dev';
35+
36+
switch (manager) {
37+
case 'npm':
38+
return npm;
39+
case 'yarn':
40+
return yarn;
41+
case 'pnpm':
42+
return pnpm;
43+
default:
44+
return fs.existsSync(path.join(process.cwd(), 'yarn.lock')) ? yarn : npm;
45+
}
3546
}
3647

3748
export function runCommand(cmd: string) {

src/main.ts

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ async function runApp(app: Command) {
1313

1414
app
1515
.command('init')
16+
.option(
17+
'-i, --installer <installer>',
18+
'Explicitly set the package manager to use'
19+
)
20+
.option('-p, --preserve', 'Preserve existing CSS')
1621
.description('Initialize TailwindCSS in the current project')
1722
.action(InitCommand);
1823

src/processor.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import fs from 'fs-extra';
22
import chalk from 'chalk';
3-
import { Framework } from './types';
3+
import { Framework, InitOptions } from './types';
44
import { CSS_STUB } from './constants';
5-
import { detectInstaller, runCommand } from './helpers';
5+
import { installerPrefix, runCommand } from './helpers';
66
import { setupContent } from './content';
77
import ora from 'ora';
88

9-
export async function handle(framework: Framework) {
9+
export async function handle(framework: Framework, options: InitOptions) {
1010
const { requiredDependencies, initCommands, cssLocation, steps } = framework;
11-
const installer = detectInstaller();
11+
const installer = installerPrefix(options.installer);
1212

1313
// Install required dependencies
1414
if (requiredDependencies.length) {
@@ -39,7 +39,10 @@ export async function handle(framework: Framework) {
3939
);
4040
fs.ensureFileSync(cssLocation);
4141
const exitingCss = fs.readFileSync(cssLocation, 'utf8');
42-
fs.writeFileSync(cssLocation, `${exitingCss}\n\n${CSS_STUB}`);
42+
const updatedCss = !options.preserve
43+
? CSS_STUB
44+
: `${exitingCss}\n\n${CSS_STUB}`;
45+
fs.writeFileSync(cssLocation, updatedCss);
4346

4447
await setupContent(framework);
4548

src/types.ts

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import { drivers } from './drivers';
22

3+
export type PackageManager = 'npm' | 'yarn' | 'pnpm';
4+
5+
export interface InitOptions {
6+
preserve?: boolean;
7+
installer?: PackageManager;
8+
}
9+
310
export interface Step {
411
(): Promise<void>;
512
}

tests/helpers.spec.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import fs from 'fs-extra';
22
import { exec } from 'child_process';
3-
import { detectFramework, detectInstaller, runCommand } from '../src/helpers';
3+
import { detectFramework, installerPrefix, runCommand } from '../src/helpers';
44

55
vi.mock('child_process');
66

@@ -46,10 +46,14 @@ describe('Helpers', () => {
4646
const dep = vi.spyOn(fs, 'existsSync');
4747

4848
dep.mockReturnValue(true);
49-
expect(detectInstaller()).toBe('yarn add --dev');
49+
expect(installerPrefix()).toBe('yarn add --dev');
5050

5151
dep.mockReturnValue(false);
52-
expect(detectInstaller()).toBe('npm install --save-dev');
52+
expect(installerPrefix()).toBe('npm install --save-dev');
53+
54+
expect(installerPrefix('pnpm')).toBe('pnpm install --save-dev');
55+
expect(installerPrefix('npm')).toBe('npm install --save-dev');
56+
expect(installerPrefix('yarn')).toBe('yarn add --dev');
5357
});
5458

5559
it('can run command', async () => {

tests/main.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ vi.mock('commander', () => {
77
description: vi.fn().mockReturnThis(),
88
version: vi.fn().mockReturnThis(),
99
command: vi.fn().mockReturnThis(),
10+
option: vi.fn().mockReturnThis(),
1011
parse: vi.fn().mockReturnThis(),
1112
action: vi.fn().mockReturnThis(),
1213
},

tests/processor.spec.ts

+40-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import fs from 'fs-extra';
2+
import { CSS_STUB } from '../src/constants';
23
import * as content from '../src/content';
34
import * as helpers from '../src/helpers';
45
import { handle } from '../src/processor';
56
import { Framework } from '../src/types';
67

78
describe('Processor', () => {
9+
beforeAll(() => {
10+
vi.stubGlobal('console', { ...console, log: vi.fn() });
11+
});
12+
813
afterEach(() => {
914
vi.clearAllMocks();
1015
});
@@ -13,8 +18,39 @@ describe('Processor', () => {
1318
vi.stubGlobal('console', { log: vi.fn() });
1419
vi.spyOn(fs, 'ensureFileSync').mockReturnValue();
1520
vi.spyOn(fs, 'readFileSync').mockReturnValue('');
16-
vi.spyOn(fs, 'writeFileSync').mockReturnValue();
17-
vi.spyOn(helpers, 'detectInstaller').mockReturnValue('npm');
21+
const write = vi.spyOn(fs, 'writeFileSync').mockReturnValue();
22+
vi.spyOn(helpers, 'installerPrefix').mockReturnValue('npm');
23+
const runner = vi
24+
.spyOn(helpers, 'runCommand')
25+
.mockReturnValue(Promise.resolve());
26+
const setup = vi.spyOn(content, 'setupContent').mockResolvedValue();
27+
const step = vi.fn().mockResolvedValue(true);
28+
const framework: Framework = {
29+
content: {
30+
name: 'content',
31+
files: [],
32+
},
33+
requiredDependencies: ['deps'],
34+
initCommands: ['init'],
35+
cssLocation: 'css',
36+
steps: [step],
37+
};
38+
39+
await handle(framework, {});
40+
41+
expect(runner).toHaveBeenCalledWith('npm deps');
42+
expect(runner).toHaveBeenCalledWith('init');
43+
expect(setup).toHaveBeenCalledWith(framework);
44+
expect(step).toHaveBeenCalled();
45+
expect(write).toHaveBeenCalledWith('css', CSS_STUB);
46+
});
47+
48+
it('will process a framework driver with replace', async () => {
49+
vi.stubGlobal('console', { log: vi.fn() });
50+
vi.spyOn(fs, 'ensureFileSync').mockReturnValue();
51+
vi.spyOn(fs, 'readFileSync').mockReturnValue('existing');
52+
const write = vi.spyOn(fs, 'writeFileSync').mockReturnValue();
53+
vi.spyOn(helpers, 'installerPrefix').mockReturnValue('npm');
1854
const runner = vi
1955
.spyOn(helpers, 'runCommand')
2056
.mockReturnValue(Promise.resolve());
@@ -31,11 +67,12 @@ describe('Processor', () => {
3167
steps: [step],
3268
};
3369

34-
await handle(framework);
70+
await handle(framework, { preserve: true });
3571

3672
expect(runner).toHaveBeenCalledWith('npm deps');
3773
expect(runner).toHaveBeenCalledWith('init');
3874
expect(setup).toHaveBeenCalledWith(framework);
3975
expect(step).toHaveBeenCalled();
76+
expect(write).toHaveBeenCalledWith('css', 'existing\n\n' + CSS_STUB);
4077
});
4178
});

0 commit comments

Comments
 (0)