rnsup 1.0.0
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/LICENSE +7 -0
- package/README.md +331 -0
- package/bin/rnsup.js +2 -0
- package/dist/commands/generateComponent.js +70 -0
- package/dist/commands/generateScreen.js +84 -0
- package/dist/commands/setup.js +145 -0
- package/dist/index.js +34 -0
- package/dist/templates/component.js +24 -0
- package/dist/templates/screen.js +26 -0
- package/dist/utils/alias.js +62 -0
- package/dist/utils/aliasManager.js +57 -0
- package/dist/utils/config.js +20 -0
- package/dist/utils/createApiClient.js +48 -0
- package/dist/utils/createDocs.js +65 -0
- package/dist/utils/createResponsive.js +50 -0
- package/dist/utils/createTypes.js +19 -0
- package/dist/utils/detectProject.js +21 -0
- package/dist/utils/file.js +25 -0
- package/dist/utils/handleCancel.js +14 -0
- package/dist/utils/history.js +24 -0
- package/dist/utils/install.js +29 -0
- package/dist/utils/lockfile.js +25 -0
- package/dist/utils/packageManager.js +23 -0
- package/dist/utils/parseComponentName.js +29 -0
- package/dist/utils/parseName.js +44 -0
- package/dist/utils/patchIndex.js +19 -0
- package/dist/utils/selectPrompt.js +34 -0
- package/package.json +67 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.screenTemplate = screenTemplate;
|
|
4
|
+
function screenTemplate(name) {
|
|
5
|
+
return `import React from 'react';
|
|
6
|
+
import { View, Text, StyleSheet } from 'react-native';
|
|
7
|
+
|
|
8
|
+
const ${name} = () => {
|
|
9
|
+
return (
|
|
10
|
+
<View style={styles.container}>
|
|
11
|
+
<Text>${name}</Text>
|
|
12
|
+
</View>
|
|
13
|
+
);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default ${name};
|
|
17
|
+
|
|
18
|
+
const styles = StyleSheet.create({
|
|
19
|
+
container: {
|
|
20
|
+
flex: 1,
|
|
21
|
+
alignItems: 'center',
|
|
22
|
+
justifyContent: 'center',
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
`;
|
|
26
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.setupTsAlias = setupTsAlias;
|
|
7
|
+
exports.setupBabelAlias = setupBabelAlias;
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
/* ---------- TS CONFIG ---------- */
|
|
11
|
+
async function setupTsAlias() {
|
|
12
|
+
const tsconfigPath = path_1.default.join(process.cwd(), 'tsconfig.json');
|
|
13
|
+
if (!(await fs_extra_1.default.pathExists(tsconfigPath)))
|
|
14
|
+
return;
|
|
15
|
+
const tsconfig = await fs_extra_1.default.readJson(tsconfigPath);
|
|
16
|
+
if (!tsconfig.compilerOptions)
|
|
17
|
+
tsconfig.compilerOptions = {};
|
|
18
|
+
if (!tsconfig.compilerOptions.paths)
|
|
19
|
+
tsconfig.compilerOptions.paths = {};
|
|
20
|
+
tsconfig.compilerOptions.baseUrl = '.';
|
|
21
|
+
Object.assign(tsconfig.compilerOptions.paths, {
|
|
22
|
+
'@src/*': ['src/*'],
|
|
23
|
+
'@components/*': ['src/components/*'],
|
|
24
|
+
'@features/*': ['src/features/*'],
|
|
25
|
+
'@utils/*': ['src/utils/*'],
|
|
26
|
+
'@services/*': ['src/services/*'],
|
|
27
|
+
'@store/*': ['src/store/*'],
|
|
28
|
+
'@hooks/*': ['src/hooks/*'],
|
|
29
|
+
'@theme/*': ['src/theme/*'],
|
|
30
|
+
'@assets/*': ['src/assets/*']
|
|
31
|
+
});
|
|
32
|
+
await fs_extra_1.default.writeJson(tsconfigPath, tsconfig, { spaces: 2 });
|
|
33
|
+
}
|
|
34
|
+
/* ---------- BABEL CONFIG ---------- */
|
|
35
|
+
async function setupBabelAlias() {
|
|
36
|
+
const babelPath = path_1.default.join(process.cwd(), 'babel.config.js');
|
|
37
|
+
if (!(await fs_extra_1.default.pathExists(babelPath)))
|
|
38
|
+
return;
|
|
39
|
+
const content = `
|
|
40
|
+
module.exports = {
|
|
41
|
+
presets: ['module:@react-native/babel-preset'],
|
|
42
|
+
plugins: [
|
|
43
|
+
['module-resolver', {
|
|
44
|
+
root: ['./src'],
|
|
45
|
+
alias: {
|
|
46
|
+
'@src': './src',
|
|
47
|
+
'@components': './src/components',
|
|
48
|
+
'@features': './src/features',
|
|
49
|
+
'@utils': './src/utils',
|
|
50
|
+
'@services': './src/services',
|
|
51
|
+
'@store': './src/store',
|
|
52
|
+
'@hooks': './src/hooks',
|
|
53
|
+
'@theme': './src/theme',
|
|
54
|
+
'@assets': './src/assets'
|
|
55
|
+
}
|
|
56
|
+
}],
|
|
57
|
+
'react-native-worklets/plugin'
|
|
58
|
+
]
|
|
59
|
+
};
|
|
60
|
+
`;
|
|
61
|
+
await fs_extra_1.default.writeFile(babelPath, content);
|
|
62
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerAlias = registerAlias;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* Register new alias in tsconfig + babel automatically
|
|
11
|
+
*/
|
|
12
|
+
async function registerAlias(relativeDir) {
|
|
13
|
+
// example: src/payments/checkout
|
|
14
|
+
if (!relativeDir.startsWith('src/'))
|
|
15
|
+
return;
|
|
16
|
+
const parts = relativeDir.replace('src/', '').split('/');
|
|
17
|
+
const baseAlias = parts[0];
|
|
18
|
+
// we only create alias for first level
|
|
19
|
+
// ex: src/payments/... => @payments
|
|
20
|
+
const aliasKey = `@${baseAlias}`;
|
|
21
|
+
const aliasPath = `./src/${baseAlias}`;
|
|
22
|
+
await updateTSConfig(aliasKey, aliasPath);
|
|
23
|
+
await updateBabel(aliasKey, aliasPath);
|
|
24
|
+
}
|
|
25
|
+
/* ---------------- TS CONFIG ---------------- */
|
|
26
|
+
async function updateTSConfig(aliasKey, aliasPath) {
|
|
27
|
+
const tsconfigPath = path_1.default.join(process.cwd(), 'tsconfig.json');
|
|
28
|
+
if (!(await fs_extra_1.default.pathExists(tsconfigPath)))
|
|
29
|
+
return;
|
|
30
|
+
const tsconfig = await fs_extra_1.default.readJson(tsconfigPath);
|
|
31
|
+
if (!tsconfig.compilerOptions)
|
|
32
|
+
tsconfig.compilerOptions = {};
|
|
33
|
+
if (!tsconfig.compilerOptions.paths)
|
|
34
|
+
tsconfig.compilerOptions.paths = {};
|
|
35
|
+
if (!tsconfig.compilerOptions.paths[`${aliasKey}/*`]) {
|
|
36
|
+
tsconfig.compilerOptions.paths[`${aliasKey}/*`] = [`${aliasPath}/*`];
|
|
37
|
+
await fs_extra_1.default.writeJson(tsconfigPath, tsconfig, { spaces: 2 });
|
|
38
|
+
console.log(`Alias added in tsconfig: ${aliasKey}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/* ---------------- BABEL ---------------- */
|
|
42
|
+
async function updateBabel(aliasKey, aliasPath) {
|
|
43
|
+
const babelPath = path_1.default.join(process.cwd(), 'babel.config.js');
|
|
44
|
+
if (!(await fs_extra_1.default.pathExists(babelPath)))
|
|
45
|
+
return;
|
|
46
|
+
let content = await fs_extra_1.default.readFile(babelPath, 'utf8');
|
|
47
|
+
if (content.includes(aliasKey))
|
|
48
|
+
return;
|
|
49
|
+
const insertPoint = content.indexOf('alias: {');
|
|
50
|
+
if (insertPoint === -1)
|
|
51
|
+
return;
|
|
52
|
+
const updated = content.slice(0, insertPoint + 8) +
|
|
53
|
+
`\n '${aliasKey}': '${aliasPath}',` +
|
|
54
|
+
content.slice(insertPoint + 8);
|
|
55
|
+
await fs_extra_1.default.writeFile(babelPath, updated);
|
|
56
|
+
console.log(`Alias added in babel: ${aliasKey}`);
|
|
57
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.saveConfig = saveConfig;
|
|
7
|
+
exports.readConfig = readConfig;
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const DIR = path_1.default.join(process.cwd(), '.rnsup');
|
|
11
|
+
const CONFIG = path_1.default.join(DIR, 'config.json');
|
|
12
|
+
async function saveConfig(data) {
|
|
13
|
+
await fs_extra_1.default.ensureDir(DIR);
|
|
14
|
+
await fs_extra_1.default.writeJson(CONFIG, data, { spaces: 2 });
|
|
15
|
+
}
|
|
16
|
+
async function readConfig() {
|
|
17
|
+
if (!(await fs_extra_1.default.pathExists(CONFIG)))
|
|
18
|
+
return null;
|
|
19
|
+
return fs_extra_1.default.readJson(CONFIG);
|
|
20
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createApiClient = createApiClient;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
async function createApiClient() {
|
|
10
|
+
const filePath = path_1.default.join(process.cwd(), 'src/services/api/client.ts');
|
|
11
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
|
|
12
|
+
const content = `
|
|
13
|
+
import axios from 'axios';
|
|
14
|
+
|
|
15
|
+
const api = axios.create({
|
|
16
|
+
baseURL: 'https://api.example.com',
|
|
17
|
+
timeout: 15000,
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// request interceptor
|
|
24
|
+
api.interceptors.request.use(
|
|
25
|
+
async config => {
|
|
26
|
+
// TODO: attach token here
|
|
27
|
+
// const token = await getToken();
|
|
28
|
+
// if (token) config.headers.Authorization = \`Bearer \${token}\`;
|
|
29
|
+
return config;
|
|
30
|
+
},
|
|
31
|
+
error => Promise.reject(error)
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// response interceptor
|
|
35
|
+
api.interceptors.response.use(
|
|
36
|
+
response => response.data,
|
|
37
|
+
async error => {
|
|
38
|
+
if (error.response?.status === 401) {
|
|
39
|
+
// handle logout or refresh token
|
|
40
|
+
}
|
|
41
|
+
return Promise.reject(error);
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
export default api;
|
|
46
|
+
`;
|
|
47
|
+
await fs_extra_1.default.writeFile(filePath, content.trim());
|
|
48
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createDocs = createDocs;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
async function createDocs() {
|
|
10
|
+
const filePath = path_1.default.join(process.cwd(), 'RNSUP.md');
|
|
11
|
+
const content = `
|
|
12
|
+
# RNSUP Project Guide
|
|
13
|
+
|
|
14
|
+
## What RNSUP Did
|
|
15
|
+
This project was configured using RNSUP CLI.
|
|
16
|
+
|
|
17
|
+
RNSUP automatically:
|
|
18
|
+
- Installed navigation
|
|
19
|
+
- Configured reanimated
|
|
20
|
+
- Setup alias imports
|
|
21
|
+
- Added axios API client
|
|
22
|
+
- Added responsive utilities
|
|
23
|
+
- Added image import support
|
|
24
|
+
|
|
25
|
+
## Folder Structure
|
|
26
|
+
|
|
27
|
+
src/
|
|
28
|
+
components/
|
|
29
|
+
features/
|
|
30
|
+
services/
|
|
31
|
+
store/
|
|
32
|
+
utils/
|
|
33
|
+
hooks/
|
|
34
|
+
theme/
|
|
35
|
+
types/
|
|
36
|
+
|
|
37
|
+
## Alias Usage
|
|
38
|
+
|
|
39
|
+
Instead of:
|
|
40
|
+
import Button from '../../../components/Button'
|
|
41
|
+
|
|
42
|
+
Use:
|
|
43
|
+
import Button from '@components/Button'
|
|
44
|
+
|
|
45
|
+
## Responsive Usage
|
|
46
|
+
|
|
47
|
+
import { widthPercentageToDP as wp } from '@utils/responsive-screen';
|
|
48
|
+
|
|
49
|
+
<View style={{ width: wp(80) }} />
|
|
50
|
+
|
|
51
|
+
## API Usage
|
|
52
|
+
|
|
53
|
+
import api from '@services/api/client';
|
|
54
|
+
|
|
55
|
+
const users = await api.get('/users');
|
|
56
|
+
|
|
57
|
+
## Image Import
|
|
58
|
+
|
|
59
|
+
import logo from '@assets/logo.png';
|
|
60
|
+
|
|
61
|
+
<Image source={logo} />
|
|
62
|
+
|
|
63
|
+
`;
|
|
64
|
+
await fs_extra_1.default.writeFile(filePath, content.trim());
|
|
65
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createResponsiveFile = createResponsiveFile;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
async function createResponsiveFile() {
|
|
10
|
+
const filePath = path_1.default.join(process.cwd(), 'src/utils/responsive-screen.ts');
|
|
11
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
|
|
12
|
+
const content = `
|
|
13
|
+
import { Dimensions, PixelRatio, ScaledSize } from 'react-native';
|
|
14
|
+
|
|
15
|
+
let screenWidth: number = Dimensions.get('window').width;
|
|
16
|
+
let screenHeight: number = Dimensions.get('window').height;
|
|
17
|
+
|
|
18
|
+
export const widthPercentageToDP = (widthPercent: string | number): number => {
|
|
19
|
+
const elemWidth = typeof widthPercent === "number" ? widthPercent : parseFloat(widthPercent);
|
|
20
|
+
return PixelRatio.roundToNearestPixel(screenWidth * elemWidth / 100);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const heightPercentageToDP = (heightPercent: string | number): number => {
|
|
24
|
+
const elemHeight = typeof heightPercent === "number" ? heightPercent : parseFloat(heightPercent);
|
|
25
|
+
return PixelRatio.roundToNearestPixel(screenHeight * elemHeight / 100);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
type OrientationType = 'portrait' | 'landscape';
|
|
29
|
+
|
|
30
|
+
interface OrientationConfig {
|
|
31
|
+
setOrientation: (orientation: OrientationType) => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const listenOrientationChange = (config: OrientationConfig): (() => void) => {
|
|
35
|
+
const updateDimensions = ({ window }: { window: ScaledSize }): void => {
|
|
36
|
+
screenWidth = window.width;
|
|
37
|
+
screenHeight = window.height;
|
|
38
|
+
const newOrientation: OrientationType = screenWidth < screenHeight ? 'portrait' : 'landscape';
|
|
39
|
+
config.setOrientation(newOrientation);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const subscription = Dimensions.addEventListener('change', updateDimensions);
|
|
43
|
+
|
|
44
|
+
return () => {
|
|
45
|
+
subscription.remove();
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
`;
|
|
49
|
+
await fs_extra_1.default.writeFile(filePath, content.trim());
|
|
50
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createTypes = createTypes;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
async function createTypes() {
|
|
10
|
+
const filePath = path_1.default.join(process.cwd(), 'src/types/assets.d.ts');
|
|
11
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
|
|
12
|
+
const content = `
|
|
13
|
+
declare module "*.png";
|
|
14
|
+
declare module "*.jpg";
|
|
15
|
+
declare module "*.jpeg";
|
|
16
|
+
declare module "*.svg";
|
|
17
|
+
`;
|
|
18
|
+
await fs_extra_1.default.writeFile(filePath, content.trim());
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isReactNativeProject = isReactNativeProject;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
function isReactNativeProject() {
|
|
10
|
+
const root = process.cwd();
|
|
11
|
+
const packageJson = path_1.default.join(root, 'package.json');
|
|
12
|
+
const androidFolder = path_1.default.join(root, 'android');
|
|
13
|
+
const iosFolder = path_1.default.join(root, 'ios');
|
|
14
|
+
if (!fs_1.default.existsSync(packageJson))
|
|
15
|
+
return false;
|
|
16
|
+
if (!fs_1.default.existsSync(androidFolder))
|
|
17
|
+
return false;
|
|
18
|
+
if (!fs_1.default.existsSync(iosFolder))
|
|
19
|
+
return false;
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createBaseFolders = createBaseFolders;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
async function createBaseFolders() {
|
|
10
|
+
const root = process.cwd();
|
|
11
|
+
const folders = [
|
|
12
|
+
'src',
|
|
13
|
+
'src/components',
|
|
14
|
+
'src/features',
|
|
15
|
+
'src/services',
|
|
16
|
+
'src/hooks',
|
|
17
|
+
'src/utils',
|
|
18
|
+
'src/store',
|
|
19
|
+
'src/theme',
|
|
20
|
+
'src/assets'
|
|
21
|
+
];
|
|
22
|
+
for (const folder of folders) {
|
|
23
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(root, folder));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleCancel = handleCancel;
|
|
4
|
+
function handleCancel(error) {
|
|
5
|
+
// Inquirer Ctrl+C cancellation
|
|
6
|
+
if (error?.name === 'ExitPromptError' ||
|
|
7
|
+
error?.message?.includes('SIGINT')) {
|
|
8
|
+
console.log('\nOperation cancelled by user.\n');
|
|
9
|
+
process.exit(0);
|
|
10
|
+
}
|
|
11
|
+
// real error
|
|
12
|
+
console.error('\nSetup failed:\n', error);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.addHistory = addHistory;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const FILE = path_1.default.join(process.cwd(), '.rnsup', 'history.json');
|
|
10
|
+
async function addHistory(action) {
|
|
11
|
+
await fs_extra_1.default.ensureFile(FILE);
|
|
12
|
+
let list = [];
|
|
13
|
+
try {
|
|
14
|
+
list = await fs_extra_1.default.readJson(FILE);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
list = [];
|
|
18
|
+
}
|
|
19
|
+
list.push({
|
|
20
|
+
action,
|
|
21
|
+
date: new Date().toISOString()
|
|
22
|
+
});
|
|
23
|
+
await fs_extra_1.default.writeJson(FILE, list, { spaces: 2 });
|
|
24
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.installPackages = installPackages;
|
|
4
|
+
const execa_1 = require("execa");
|
|
5
|
+
async function installPackages(manager, packages, dev = false) {
|
|
6
|
+
if (!packages.length)
|
|
7
|
+
return;
|
|
8
|
+
let cmd = '';
|
|
9
|
+
let args = [];
|
|
10
|
+
if (manager === 'yarn') {
|
|
11
|
+
cmd = 'yarn';
|
|
12
|
+
args = ['add', ...packages];
|
|
13
|
+
if (dev)
|
|
14
|
+
args.push('-D');
|
|
15
|
+
}
|
|
16
|
+
else if (manager === 'pnpm') {
|
|
17
|
+
cmd = 'pnpm';
|
|
18
|
+
args = ['add', ...packages];
|
|
19
|
+
if (dev)
|
|
20
|
+
args.push('-D');
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
cmd = 'npm';
|
|
24
|
+
args = ['install', ...packages];
|
|
25
|
+
if (dev)
|
|
26
|
+
args.push('--save-dev');
|
|
27
|
+
}
|
|
28
|
+
await (0, execa_1.execa)(cmd, args, { stdio: 'inherit' });
|
|
29
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fixLockFile = fixLockFile;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
async function fixLockFile(manager) {
|
|
10
|
+
const root = process.cwd();
|
|
11
|
+
const npmLock = path_1.default.join(root, 'package-lock.json');
|
|
12
|
+
const yarnLock = path_1.default.join(root, 'yarn.lock');
|
|
13
|
+
if (manager === 'yarn') {
|
|
14
|
+
if (await fs_extra_1.default.pathExists(npmLock)) {
|
|
15
|
+
await fs_extra_1.default.remove(npmLock);
|
|
16
|
+
console.log('Removed package-lock.json (using yarn)');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (manager === 'npm') {
|
|
20
|
+
if (await fs_extra_1.default.pathExists(yarnLock)) {
|
|
21
|
+
await fs_extra_1.default.remove(yarnLock);
|
|
22
|
+
console.log('Removed yarn.lock (using npm)');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isInstalled = isInstalled;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
function isInstalled(manager) {
|
|
6
|
+
try {
|
|
7
|
+
if (manager === 'yarn') {
|
|
8
|
+
(0, child_process_1.execSync)('yarn --version', { stdio: 'ignore' });
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
if (manager === 'pnpm') {
|
|
12
|
+
(0, child_process_1.execSync)('pnpm --version', { stdio: 'ignore' });
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
// npm always exists with node
|
|
16
|
+
if (manager === 'npm')
|
|
17
|
+
return true;
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseComponentName = parseComponentName;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
function parseComponentName(input) {
|
|
9
|
+
// normalize slashes
|
|
10
|
+
let cleaned = input.replace(/\\/g, '/').trim();
|
|
11
|
+
// remove src prefix if user typed
|
|
12
|
+
if (cleaned.startsWith('src/')) {
|
|
13
|
+
cleaned = cleaned.substring(4);
|
|
14
|
+
}
|
|
15
|
+
const parts = cleaned.split('/');
|
|
16
|
+
const rawName = parts.pop();
|
|
17
|
+
// Ensure PascalCase name
|
|
18
|
+
const componentName = rawName.charAt(0).toUpperCase() + rawName.slice(1);
|
|
19
|
+
// Always inside components
|
|
20
|
+
const relativeDir = parts.length > 0
|
|
21
|
+
? `src/components/${parts.join('/')}`
|
|
22
|
+
: 'src/components';
|
|
23
|
+
const fullDir = path_1.default.join(process.cwd(), relativeDir);
|
|
24
|
+
return {
|
|
25
|
+
componentName,
|
|
26
|
+
fullDir,
|
|
27
|
+
relativeDir
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseScreenName = parseScreenName;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
/**
|
|
10
|
+
* Resolve correct location based on user input
|
|
11
|
+
*/
|
|
12
|
+
async function parseScreenName(input) {
|
|
13
|
+
// normalize slashes
|
|
14
|
+
let cleaned = input.replace(/\\/g, '/').trim();
|
|
15
|
+
// remove extension if user typed
|
|
16
|
+
cleaned = cleaned.replace(/\.tsx?$/, '');
|
|
17
|
+
// remove src prefix if provided
|
|
18
|
+
if (cleaned.startsWith('src/')) {
|
|
19
|
+
cleaned = cleaned.substring(4);
|
|
20
|
+
}
|
|
21
|
+
const parts = cleaned.split('/');
|
|
22
|
+
const rawName = parts.pop();
|
|
23
|
+
// ensure proper screen naming
|
|
24
|
+
const screenName = rawName.replace(/screen$/i, '') + 'Screen';
|
|
25
|
+
// if only name passed
|
|
26
|
+
if (parts.length === 0) {
|
|
27
|
+
const dir = path_1.default.join(process.cwd(), 'src/screens');
|
|
28
|
+
return {
|
|
29
|
+
screenName,
|
|
30
|
+
fullDir: dir,
|
|
31
|
+
relativeDir: 'src/screens'
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// user provided folder path
|
|
35
|
+
const relativeDir = `src/${parts.join('/')}`;
|
|
36
|
+
const fullDir = path_1.default.join(process.cwd(), relativeDir);
|
|
37
|
+
// if folder does not exist, confirm creation later
|
|
38
|
+
await fs_extra_1.default.ensureDir(fullDir);
|
|
39
|
+
return {
|
|
40
|
+
screenName,
|
|
41
|
+
fullDir,
|
|
42
|
+
relativeDir
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.patchIndexFile = patchIndexFile;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
async function patchIndexFile() {
|
|
10
|
+
const indexPath = path_1.default.join(process.cwd(), 'index.js');
|
|
11
|
+
if (!(await fs_extra_1.default.pathExists(indexPath)))
|
|
12
|
+
return;
|
|
13
|
+
let content = await fs_extra_1.default.readFile(indexPath, 'utf8');
|
|
14
|
+
if (content.includes("react-native-gesture-handler"))
|
|
15
|
+
return;
|
|
16
|
+
content =
|
|
17
|
+
`import 'react-native-gesture-handler';\n` + content;
|
|
18
|
+
await fs_extra_1.default.writeFile(indexPath, content);
|
|
19
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.selectOption = selectOption;
|
|
7
|
+
const readline_1 = __importDefault(require("readline"));
|
|
8
|
+
/**
|
|
9
|
+
* Numeric select prompt
|
|
10
|
+
* Returns a typed value instead of raw string
|
|
11
|
+
*/
|
|
12
|
+
async function selectOption(message, options) {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
console.log('\n\x1b[1;36m' + message + '\x1b[0m');
|
|
15
|
+
options.forEach((opt, i) => {
|
|
16
|
+
console.log(`${i + 1}) ${opt}`);
|
|
17
|
+
});
|
|
18
|
+
const rl = readline_1.default.createInterface({
|
|
19
|
+
input: process.stdin,
|
|
20
|
+
output: process.stdout
|
|
21
|
+
});
|
|
22
|
+
rl.question('\x1b[1;33mEnter choice number: \x1b[0m', (answer) => {
|
|
23
|
+
const index = Number(answer) - 1;
|
|
24
|
+
rl.close();
|
|
25
|
+
if (index >= 0 && index < options.length) {
|
|
26
|
+
resolve(options[index]);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
console.log('\x1b[1;31mInvalid selection. Defaulting to first option.\x1b[0m');
|
|
30
|
+
resolve(options[0]);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|