@aex.is/zero 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/config/frameworks.js +95 -0
- package/dist/config/modules.js +69 -0
- package/dist/engine/env.js +10 -0
- package/dist/engine/installers.js +36 -0
- package/dist/engine/scaffold.js +251 -0
- package/{src/engine/templates.ts → dist/engine/templates.js} +1 -8
- package/dist/env/detect.js +36 -0
- package/dist/index.js +39 -0
- package/dist/types.js +1 -0
- package/dist/ui/App.js +75 -0
- package/dist/ui/components/SelectList.js +67 -0
- package/dist/ui/screens/Confirm.js +22 -0
- package/dist/ui/screens/DomainPrompt.js +11 -0
- package/dist/ui/screens/FrameworkSelect.js +12 -0
- package/dist/ui/screens/Intro.js +18 -0
- package/dist/ui/screens/ModuleSelect.js +12 -0
- package/dist/ui/screens/NamePrompt.js +18 -0
- package/package.json +6 -5
- package/src/config/frameworks.ts +0 -110
- package/src/config/modules.ts +0 -82
- package/src/engine/env.ts +0 -12
- package/src/engine/installers.ts +0 -44
- package/src/engine/scaffold.ts +0 -296
- package/src/env/detect.ts +0 -40
- package/src/index.ts +0 -48
- package/src/types.ts +0 -12
- package/src/ui/App.tsx +0 -139
- package/src/ui/components/SelectList.tsx +0 -114
- package/src/ui/screens/Confirm.tsx +0 -62
- package/src/ui/screens/DomainPrompt.tsx +0 -29
- package/src/ui/screens/FrameworkSelect.tsx +0 -34
- package/src/ui/screens/Intro.tsx +0 -31
- package/src/ui/screens/ModuleSelect.tsx +0 -34
- package/src/ui/screens/NamePrompt.tsx +0 -37
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
export function SelectList({ items, selectedIds, onChange, onSubmit, multi = false, hint }) {
|
|
5
|
+
const [index, setIndex] = useState(0);
|
|
6
|
+
const selectedSet = useMemo(() => new Set(selectedIds), [selectedIds]);
|
|
7
|
+
const move = useCallback((delta) => {
|
|
8
|
+
setIndex((current) => {
|
|
9
|
+
const next = current + delta;
|
|
10
|
+
if (next < 0) {
|
|
11
|
+
return items.length - 1;
|
|
12
|
+
}
|
|
13
|
+
if (next >= items.length) {
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
return next;
|
|
17
|
+
});
|
|
18
|
+
}, [items.length]);
|
|
19
|
+
const toggle = useCallback((itemId) => {
|
|
20
|
+
if (multi) {
|
|
21
|
+
const next = new Set(selectedSet);
|
|
22
|
+
if (next.has(itemId)) {
|
|
23
|
+
next.delete(itemId);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
next.add(itemId);
|
|
27
|
+
}
|
|
28
|
+
onChange(Array.from(next));
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
onChange([itemId]);
|
|
32
|
+
}
|
|
33
|
+
}, [multi, onChange, selectedSet]);
|
|
34
|
+
useInput((input, key) => {
|
|
35
|
+
if (key.upArrow) {
|
|
36
|
+
move(-1);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (key.downArrow) {
|
|
40
|
+
move(1);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (input === ' ') {
|
|
44
|
+
const item = items[index];
|
|
45
|
+
if (item) {
|
|
46
|
+
toggle(item.id);
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (key.return) {
|
|
51
|
+
onSubmit();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { flexDirection: "column", children: items.map((item, idx) => {
|
|
55
|
+
const isSelected = selectedSet.has(item.id);
|
|
56
|
+
const isActive = idx === index;
|
|
57
|
+
const prefix = isActive ? '>' : ' ';
|
|
58
|
+
const marker = multi
|
|
59
|
+
? isSelected
|
|
60
|
+
? '[x]'
|
|
61
|
+
: '[ ]'
|
|
62
|
+
: isSelected
|
|
63
|
+
? '(x)'
|
|
64
|
+
: '( )';
|
|
65
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: isActive ? 'cyan' : undefined, children: [prefix, " ", marker, " ", item.label] }), item.description ? (_jsxs(Text, { color: "gray", children: [" ", item.description] })) : null] }, item.id));
|
|
66
|
+
}) }), hint ? _jsx(Text, { color: "gray", children: hint }) : null] }));
|
|
67
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import { SelectList } from '../components/SelectList.js';
|
|
5
|
+
import { frameworks } from '../../config/frameworks.js';
|
|
6
|
+
import { modules } from '../../config/modules.js';
|
|
7
|
+
const actionItems = [
|
|
8
|
+
{ id: 'continue', label: 'Continue' },
|
|
9
|
+
{ id: 'edit-name', label: 'Edit name' },
|
|
10
|
+
{ id: 'edit-domain', label: 'Edit domain' },
|
|
11
|
+
{ id: 'edit-framework', label: 'Edit framework' },
|
|
12
|
+
{ id: 'edit-modules', label: 'Edit modules' },
|
|
13
|
+
{ id: 'cancel', label: 'Cancel' }
|
|
14
|
+
];
|
|
15
|
+
export function Confirm({ name, domain, framework, modules: selectedModules, onAction }) {
|
|
16
|
+
const [selection, setSelection] = useState('continue');
|
|
17
|
+
const frameworkLabel = frameworks.find((item) => item.id === framework)?.label ?? framework;
|
|
18
|
+
const moduleLabels = selectedModules
|
|
19
|
+
.map((id) => modules.find((item) => item.id === id)?.label ?? id)
|
|
20
|
+
.join(', ');
|
|
21
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "Confirm" }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["App name: ", name] }), _jsxs(Text, { children: ["Domain: ", domain || 'None'] }), _jsxs(Text, { children: ["Framework: ", frameworkLabel] }), _jsxs(Text, { children: ["Modules: ", moduleLabels || 'None'] })] }), _jsx(Box, { marginTop: 1, children: _jsx(SelectList, { items: actionItems, selectedIds: [selection], onChange: (next) => setSelection(next[0]), onSubmit: () => onAction(selection), multi: false, hint: "Select an action and press Enter." }) })] }));
|
|
22
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import TextInput from 'ink-text-input';
|
|
5
|
+
export function DomainPrompt({ initialValue, onSubmit }) {
|
|
6
|
+
const [value, setValue] = useState(initialValue);
|
|
7
|
+
const handleSubmit = () => {
|
|
8
|
+
onSubmit(value.trim());
|
|
9
|
+
};
|
|
10
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "Domain (optional)" }), _jsx(Text, { color: "gray", children: "Press Enter to continue or leave blank." }), _jsx(TextInput, { value: value, onChange: setValue, onSubmit: handleSubmit, placeholder: "example.com" })] }));
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { SelectList } from '../components/SelectList.js';
|
|
4
|
+
import { frameworks } from '../../config/frameworks.js';
|
|
5
|
+
export function FrameworkSelect({ value, onChange, onConfirm }) {
|
|
6
|
+
const items = frameworks.map((framework) => ({
|
|
7
|
+
id: framework.id,
|
|
8
|
+
label: framework.label,
|
|
9
|
+
description: framework.description
|
|
10
|
+
}));
|
|
11
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "Framework" }), _jsx(Text, { color: "gray", children: "Use arrows to move, space to select, Enter to confirm." }), _jsx(SelectList, { items: items, selectedIds: [value], onChange: (next) => onChange(next[0]), onSubmit: onConfirm, multi: false, hint: "( ) radio select" })] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, useInput } from 'ink';
|
|
3
|
+
const introArt = [
|
|
4
|
+
' _____',
|
|
5
|
+
' / ___ \\ ',
|
|
6
|
+
' / / _ \\ \\ ',
|
|
7
|
+
' | |/ /| |',
|
|
8
|
+
' \\ \\_/ / /',
|
|
9
|
+
' \\___/_/'
|
|
10
|
+
].join('\n');
|
|
11
|
+
export function Intro({ onContinue }) {
|
|
12
|
+
useInput((input, key) => {
|
|
13
|
+
if (key.return || input === ' ') {
|
|
14
|
+
onContinue();
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: introArt }), _jsx(Text, { color: "cyan", children: "Aexis Zero" }), _jsx(Text, { color: "gray", children: "Press Enter to begin." })] }));
|
|
18
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { SelectList } from '../components/SelectList.js';
|
|
4
|
+
import { modules } from '../../config/modules.js';
|
|
5
|
+
export function ModuleSelect({ value, onChange, onConfirm }) {
|
|
6
|
+
const items = modules.map((module) => ({
|
|
7
|
+
id: module.id,
|
|
8
|
+
label: module.label,
|
|
9
|
+
description: module.description
|
|
10
|
+
}));
|
|
11
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "Modules" }), _jsx(Text, { color: "gray", children: "Use arrows to move, space to toggle, Enter to confirm." }), _jsx(SelectList, { items: items, selectedIds: value, onChange: (next) => onChange(next), onSubmit: onConfirm, multi: true, hint: "[ ] multi-select" })] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import TextInput from 'ink-text-input';
|
|
5
|
+
export function NamePrompt({ initialValue, onSubmit }) {
|
|
6
|
+
const [value, setValue] = useState(initialValue);
|
|
7
|
+
const [error, setError] = useState('');
|
|
8
|
+
const handleSubmit = () => {
|
|
9
|
+
const trimmed = value.trim();
|
|
10
|
+
if (!trimmed) {
|
|
11
|
+
setError('App name is required.');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
setError('');
|
|
15
|
+
onSubmit(trimmed);
|
|
16
|
+
};
|
|
17
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "App name" }), _jsx(Text, { color: "gray", children: "Required. Press Enter to continue." }), _jsx(TextInput, { value: value, onChange: setValue, onSubmit: handleSubmit, placeholder: "my-app" }), error ? _jsx(Text, { color: "red", children: error }) : null] }));
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aex.is/zero",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Aexis Zero scaffolding CLI",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"zero": "
|
|
8
|
+
"zero": "dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"main": "dist/index.js",
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
|
-
"src",
|
|
14
13
|
"README.md",
|
|
15
14
|
"LICENSE"
|
|
16
15
|
],
|
|
@@ -19,8 +18,9 @@
|
|
|
19
18
|
},
|
|
20
19
|
"scripts": {
|
|
21
20
|
"build": "tsc -p tsconfig.json",
|
|
22
|
-
"dev": "bun run src/index.
|
|
23
|
-
"start": "node dist/index.js"
|
|
21
|
+
"dev": "bun run src/index.tsx",
|
|
22
|
+
"start": "node dist/index.js",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"execa": "^8.0.1",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"@types/node": "^20.11.30",
|
|
35
35
|
"@types/react": "^18.3.3",
|
|
36
36
|
"@types/react-dom": "^18.3.0",
|
|
37
|
+
"@types/which": "^3.0.3",
|
|
37
38
|
"typescript": "^5.5.4"
|
|
38
39
|
}
|
|
39
40
|
}
|
package/src/config/frameworks.ts
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import type { FrameworkId } from '../types.js';
|
|
2
|
-
|
|
3
|
-
export interface FrameworkDefinition {
|
|
4
|
-
id: FrameworkId;
|
|
5
|
-
label: string;
|
|
6
|
-
description: string;
|
|
7
|
-
packages: string[];
|
|
8
|
-
scaffold: {
|
|
9
|
-
command: string;
|
|
10
|
-
packageName: string;
|
|
11
|
-
argSets: string[][];
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const frameworks: FrameworkDefinition[] = [
|
|
16
|
-
{
|
|
17
|
-
id: 'nextjs',
|
|
18
|
-
label: 'Next.js',
|
|
19
|
-
description: 'React framework with App Router and Tailwind.',
|
|
20
|
-
packages: [
|
|
21
|
-
'class-variance-authority',
|
|
22
|
-
'clsx',
|
|
23
|
-
'lucide-react',
|
|
24
|
-
'tailwind-merge',
|
|
25
|
-
'tailwindcss-animate',
|
|
26
|
-
'@radix-ui/react-slot'
|
|
27
|
-
],
|
|
28
|
-
scaffold: {
|
|
29
|
-
command: 'bunx',
|
|
30
|
-
packageName: 'create-next-app@latest',
|
|
31
|
-
argSets: [
|
|
32
|
-
[
|
|
33
|
-
'--ts',
|
|
34
|
-
'--eslint',
|
|
35
|
-
'--tailwind',
|
|
36
|
-
'--turbo',
|
|
37
|
-
'--app',
|
|
38
|
-
'--no-src-dir',
|
|
39
|
-
'--import-alias',
|
|
40
|
-
'@/*',
|
|
41
|
-
'--use-bun',
|
|
42
|
-
'--skip-install'
|
|
43
|
-
],
|
|
44
|
-
[
|
|
45
|
-
'--ts',
|
|
46
|
-
'--eslint',
|
|
47
|
-
'--tailwind',
|
|
48
|
-
'--turbo',
|
|
49
|
-
'--app',
|
|
50
|
-
'--no-src-dir',
|
|
51
|
-
'--import-alias',
|
|
52
|
-
'@/*',
|
|
53
|
-
'--use-bun'
|
|
54
|
-
],
|
|
55
|
-
[
|
|
56
|
-
'--ts',
|
|
57
|
-
'--eslint',
|
|
58
|
-
'--tailwind',
|
|
59
|
-
'--turbo',
|
|
60
|
-
'--app',
|
|
61
|
-
'--no-src-dir',
|
|
62
|
-
'--import-alias',
|
|
63
|
-
'@/*'
|
|
64
|
-
],
|
|
65
|
-
[
|
|
66
|
-
'--ts',
|
|
67
|
-
'--eslint',
|
|
68
|
-
'--tailwind',
|
|
69
|
-
'--app',
|
|
70
|
-
'--no-src-dir',
|
|
71
|
-
'--import-alias',
|
|
72
|
-
'@/*'
|
|
73
|
-
]
|
|
74
|
-
]
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
id: 'expo',
|
|
79
|
-
label: 'Expo (React Native)',
|
|
80
|
-
description: 'Expo app with Router and EAS configuration.',
|
|
81
|
-
packages: [
|
|
82
|
-
'expo-router',
|
|
83
|
-
'tamagui',
|
|
84
|
-
'@tamagui/config',
|
|
85
|
-
'@tamagui/animations-react-native',
|
|
86
|
-
'@tamagui/metro-plugin',
|
|
87
|
-
'@tamagui/babel-plugin',
|
|
88
|
-
'react-native-svg'
|
|
89
|
-
],
|
|
90
|
-
scaffold: {
|
|
91
|
-
command: 'bunx',
|
|
92
|
-
packageName: 'create-expo-app',
|
|
93
|
-
argSets: [
|
|
94
|
-
['--template', 'expo-router', '--yes', '--no-install'],
|
|
95
|
-
['--template', 'expo-router', '--yes'],
|
|
96
|
-
['--yes', '--no-install'],
|
|
97
|
-
['--yes'],
|
|
98
|
-
[]
|
|
99
|
-
]
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
export function getFrameworkDefinition(id: FrameworkId): FrameworkDefinition {
|
|
105
|
-
const framework = frameworks.find((item) => item.id === id);
|
|
106
|
-
if (!framework) {
|
|
107
|
-
throw new Error(`Unknown framework: ${id}`);
|
|
108
|
-
}
|
|
109
|
-
return framework;
|
|
110
|
-
}
|
package/src/config/modules.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import type { FrameworkId, ModuleId } from '../types.js';
|
|
2
|
-
|
|
3
|
-
export interface ModuleDefinition {
|
|
4
|
-
id: ModuleId;
|
|
5
|
-
label: string;
|
|
6
|
-
description: string;
|
|
7
|
-
envVars: string[];
|
|
8
|
-
packages: Record<FrameworkId, string[]>;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const modules: ModuleDefinition[] = [
|
|
12
|
-
{
|
|
13
|
-
id: 'neon',
|
|
14
|
-
label: 'Database (Neon)',
|
|
15
|
-
description: 'Serverless Postgres with Neon.',
|
|
16
|
-
envVars: ['DATABASE_URL'],
|
|
17
|
-
packages: {
|
|
18
|
-
nextjs: ['@neondatabase/serverless'],
|
|
19
|
-
expo: ['@neondatabase/serverless']
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
id: 'clerk',
|
|
24
|
-
label: 'Auth (Clerk)',
|
|
25
|
-
description: 'Authentication with Clerk.',
|
|
26
|
-
envVars: ['CLERK_PUBLISHABLE_KEY', 'CLERK_SECRET_KEY'],
|
|
27
|
-
packages: {
|
|
28
|
-
nextjs: ['@clerk/nextjs'],
|
|
29
|
-
expo: ['@clerk/clerk-expo']
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
id: 'payload',
|
|
34
|
-
label: 'CMS (Payload)',
|
|
35
|
-
description: 'Headless CMS using Payload.',
|
|
36
|
-
envVars: ['PAYLOAD_SECRET', 'DATABASE_URL'],
|
|
37
|
-
packages: {
|
|
38
|
-
nextjs: ['payload'],
|
|
39
|
-
expo: ['payload']
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
id: 'stripe',
|
|
44
|
-
label: 'Payments (Stripe)',
|
|
45
|
-
description: 'Payments via Stripe SDK.',
|
|
46
|
-
envVars: ['STRIPE_SECRET_KEY', 'STRIPE_WEBHOOK_SECRET'],
|
|
47
|
-
packages: {
|
|
48
|
-
nextjs: ['stripe'],
|
|
49
|
-
expo: ['stripe']
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
export function getModuleDefinition(id: ModuleId): ModuleDefinition {
|
|
55
|
-
const module = modules.find((item) => item.id === id);
|
|
56
|
-
if (!module) {
|
|
57
|
-
throw new Error(`Unknown module: ${id}`);
|
|
58
|
-
}
|
|
59
|
-
return module;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function getModulePackages(moduleIds: ModuleId[], framework: FrameworkId): string[] {
|
|
63
|
-
const packages = new Set<string>();
|
|
64
|
-
for (const id of moduleIds) {
|
|
65
|
-
const module = getModuleDefinition(id);
|
|
66
|
-
for (const pkg of module.packages[framework]) {
|
|
67
|
-
packages.add(pkg);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return Array.from(packages).sort();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function getModuleEnvVars(moduleIds: ModuleId[]): string[] {
|
|
74
|
-
const envVars = new Set<string>();
|
|
75
|
-
for (const id of moduleIds) {
|
|
76
|
-
const module = getModuleDefinition(id);
|
|
77
|
-
for (const envVar of module.envVars) {
|
|
78
|
-
envVars.add(envVar);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return Array.from(envVars).sort();
|
|
82
|
-
}
|
package/src/engine/env.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import { promises as fs } from 'fs';
|
|
3
|
-
import type { ModuleId } from '../types.js';
|
|
4
|
-
import { getModuleEnvVars } from '../config/modules.js';
|
|
5
|
-
|
|
6
|
-
export async function writeEnvExample(moduleIds: ModuleId[], targetDir: string): Promise<void> {
|
|
7
|
-
const envVars = getModuleEnvVars(moduleIds);
|
|
8
|
-
const lines = envVars.map((key) => `${key}=`);
|
|
9
|
-
const content = lines.length > 0 ? `${lines.join('\n')}\n` : '';
|
|
10
|
-
const envPath = path.join(targetDir, '.env.example');
|
|
11
|
-
await fs.writeFile(envPath, content, 'utf8');
|
|
12
|
-
}
|
package/src/engine/installers.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { execa } from 'execa';
|
|
2
|
-
import type { FrameworkId, ModuleId } from '../types.js';
|
|
3
|
-
import { getModulePackages } from '../config/modules.js';
|
|
4
|
-
|
|
5
|
-
const baseEnv = {
|
|
6
|
-
...process.env,
|
|
7
|
-
CI: '1'
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export async function installBaseDependencies(targetDir: string, extraPackages: string[] = []): Promise<void> {
|
|
11
|
-
if (extraPackages.length > 0) {
|
|
12
|
-
const packages = Array.from(new Set(extraPackages)).sort();
|
|
13
|
-
await execa('bun', ['add', ...packages], {
|
|
14
|
-
cwd: targetDir,
|
|
15
|
-
stdio: 'inherit',
|
|
16
|
-
env: baseEnv,
|
|
17
|
-
shell: false
|
|
18
|
-
});
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
await execa('bun', ['install'], {
|
|
22
|
-
cwd: targetDir,
|
|
23
|
-
stdio: 'inherit',
|
|
24
|
-
env: baseEnv,
|
|
25
|
-
shell: false
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export async function installModulePackages(
|
|
30
|
-
framework: FrameworkId,
|
|
31
|
-
moduleIds: ModuleId[],
|
|
32
|
-
targetDir: string
|
|
33
|
-
): Promise<void> {
|
|
34
|
-
const packages = getModulePackages(moduleIds, framework);
|
|
35
|
-
if (packages.length === 0) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
await execa('bun', ['add', ...packages], {
|
|
39
|
-
cwd: targetDir,
|
|
40
|
-
stdio: 'inherit',
|
|
41
|
-
env: baseEnv,
|
|
42
|
-
shell: false
|
|
43
|
-
});
|
|
44
|
-
}
|