nico-tools 1.0.0 → 1.1.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/bin/cli.js +9 -13
- package/bin/commands/create-project.js +106 -0
- package/bin/commands/translate.js +12 -0
- package/bin/config/templates.js +9 -0
- package/bin/utils/file-utils.js +84 -0
- package/bin/utils/project-utils.js +49 -0
- package/package.json +4 -2
- package/templates/react-native/expo-clean-architecture/README.md +154 -0
- package/templates/react-native/expo-clean-architecture/app.config.ts +61 -0
- package/templates/react-native/expo-clean-architecture/assets/config/.gitkeep +3 -0
- package/templates/react-native/expo-clean-architecture/assets/fonts/SpaceMono-Regular.ttf +0 -0
- package/templates/react-native/expo-clean-architecture/assets/images/adaptive-icon.png +0 -0
- package/templates/react-native/expo-clean-architecture/assets/images/favicon.png +0 -0
- package/templates/react-native/expo-clean-architecture/assets/images/icon.png +0 -0
- package/templates/react-native/expo-clean-architecture/assets/images/partial-react-logo.png +0 -0
- package/templates/react-native/expo-clean-architecture/assets/images/react-logo.png +0 -0
- package/templates/react-native/expo-clean-architecture/assets/images/react-logo@2x.png +0 -0
- package/templates/react-native/expo-clean-architecture/assets/images/react-logo@3x.png +0 -0
- package/templates/react-native/expo-clean-architecture/assets/images/splash-icon.png +0 -0
- package/templates/react-native/expo-clean-architecture/babel.config.js +11 -0
- package/templates/react-native/expo-clean-architecture/docs/00-introduction.md +3 -0
- package/templates/react-native/expo-clean-architecture/docs/01-architecture.md +107 -0
- package/templates/react-native/expo-clean-architecture/package.json +78 -0
- package/templates/react-native/expo-clean-architecture/scripts/clean-src.sh +48 -0
- package/templates/react-native/expo-clean-architecture/scripts/generate-feature.sh +40 -0
- package/templates/react-native/expo-clean-architecture/src/app/(protected)/(tabs)/_layout.tsx +42 -0
- package/templates/react-native/expo-clean-architecture/src/app/(protected)/(tabs)/favorites.tsx +72 -0
- package/templates/react-native/expo-clean-architecture/src/app/(protected)/(tabs)/home.tsx +122 -0
- package/templates/react-native/expo-clean-architecture/src/app/(protected)/(tabs)/settings/_layout.tsx +5 -0
- package/templates/react-native/expo-clean-architecture/src/app/(protected)/(tabs)/settings/index.tsx +29 -0
- package/templates/react-native/expo-clean-architecture/src/app/(protected)/(tabs)/settings/profile.tsx +22 -0
- package/templates/react-native/expo-clean-architecture/src/app/(protected)/_layout.tsx +20 -0
- package/templates/react-native/expo-clean-architecture/src/app/(protected)/details.tsx +124 -0
- package/templates/react-native/expo-clean-architecture/src/app/(public)/_layout.tsx +18 -0
- package/templates/react-native/expo-clean-architecture/src/app/(public)/login.tsx +31 -0
- package/templates/react-native/expo-clean-architecture/src/app/_layout.tsx +33 -0
- package/templates/react-native/expo-clean-architecture/src/app/index.tsx +8 -0
- package/templates/react-native/expo-clean-architecture/src/core/constants/api-constants.ts +10 -0
- package/templates/react-native/expo-clean-architecture/src/core/constants/image-constants.ts +3 -0
- package/templates/react-native/expo-clean-architecture/src/core/constants/query-keys.ts +6 -0
- package/templates/react-native/expo-clean-architecture/src/core/constants/storage-keys.ts +3 -0
- package/templates/react-native/expo-clean-architecture/src/core/design/@types/color-scheme-state.ts +35 -0
- package/templates/react-native/expo-clean-architecture/src/core/design/@types/color-scheme.ts +12 -0
- package/templates/react-native/expo-clean-architecture/src/core/design/components/app-icon.tsx +16 -0
- package/templates/react-native/expo-clean-architecture/src/core/design/components/app-separator.tsx +26 -0
- package/templates/react-native/expo-clean-architecture/src/core/design/hooks/use-app-color-scheme.ts +52 -0
- package/templates/react-native/expo-clean-architecture/src/core/design/hooks/use-app-fonts.ts +12 -0
- package/templates/react-native/expo-clean-architecture/src/core/design/hooks/use-app-styles.ts +28 -0
- package/templates/react-native/expo-clean-architecture/src/core/design/theme/app-colors.ts +21 -0
- package/templates/react-native/expo-clean-architecture/src/core/design/theme/app-fonts.ts +16 -0
- package/templates/react-native/expo-clean-architecture/src/core/design/theme/app-sizes.ts +14 -0
- package/templates/react-native/expo-clean-architecture/src/core/di/injection-container.ts +53 -0
- package/templates/react-native/expo-clean-architecture/src/core/errors/index.ts +1 -0
- package/templates/react-native/expo-clean-architecture/src/core/helpers/@types.ts +23 -0
- package/templates/react-native/expo-clean-architecture/src/core/helpers/rest-client.ts +144 -0
- package/templates/react-native/expo-clean-architecture/src/core/helpers/result.ts +37 -0
- package/templates/react-native/expo-clean-architecture/src/core/helpers/usecase.ts +5 -0
- package/templates/react-native/expo-clean-architecture/src/core/hooks/use-network.ts +18 -0
- package/templates/react-native/expo-clean-architecture/src/core/i18n/@types/i18next.d.ts +11 -0
- package/templates/react-native/expo-clean-architecture/src/core/i18n/index.ts +19 -0
- package/templates/react-native/expo-clean-architecture/src/core/i18n/translations/fr.json +12 -0
- package/templates/react-native/expo-clean-architecture/src/core/services/local-storage-service-impl.ts +29 -0
- package/templates/react-native/expo-clean-architecture/src/core/services/local-storage-service.ts +26 -0
- package/templates/react-native/expo-clean-architecture/src/core/services/monitoring-service-impl.ts +15 -0
- package/templates/react-native/expo-clean-architecture/src/core/services/monitoring-service.ts +13 -0
- package/templates/react-native/expo-clean-architecture/src/core/services/network-service-impl.ts +40 -0
- package/templates/react-native/expo-clean-architecture/src/core/services/network-service.ts +16 -0
- package/templates/react-native/expo-clean-architecture/src/features/auth/@types/session-state.ts +38 -0
- package/templates/react-native/expo-clean-architecture/src/features/auth/@types/session-status-enum.ts +16 -0
- package/templates/react-native/expo-clean-architecture/src/features/auth/presentation/hooks/use-session.ts +18 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/data/datasources/favorites-datasource-impl.ts +25 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/data/datasources/favorites-datasource.ts +5 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/data/repositories/favorites-repository-impl.ts +46 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/domain/repositories/favorites-repository.ts +8 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/domain/usecases/add-to-favorites-usecase.ts +23 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/domain/usecases/clear-favorites-usecase.ts +23 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/domain/usecases/get-favorites-usecase.ts +24 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/domain/usecases/remove-from-favorites-usecase.ts +23 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/presentation/components/favorites-card.tsx +77 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/presentation/hooks/use-add-favorite.ts +24 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/presentation/hooks/use-clear-favorites.ts +22 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/presentation/hooks/use-favorites.ts +22 -0
- package/templates/react-native/expo-clean-architecture/src/features/favorites/presentation/hooks/use-remove-favorite.ts +24 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/data/datasources/movies-datasource-impl.ts +50 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/data/datasources/movies-datasource.ts +8 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/data/models/movie-details-model.ts +67 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/data/models/movie-model.ts +30 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/data/models/tmdb-response-model.ts +6 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/data/repositories/movies-repository-impl.ts +34 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/domain/entities/movie-details-entity.ts +28 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/domain/entities/movie-entity.ts +6 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/domain/repositories/movies-repository.ts +25 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/domain/usecases/get-movie-details-usecase.ts +26 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/domain/usecases/get-random-movies-usecase.ts +24 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/domain/usecases/search-movies-usecase.ts +23 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/presentation/components/movie-tile.tsx +69 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/presentation/hooks/use-movie-details.ts +22 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/presentation/hooks/use-random-movies.ts +22 -0
- package/templates/react-native/expo-clean-architecture/src/features/movies/presentation/hooks/use-search-movies.ts +22 -0
- package/templates/react-native/expo-clean-architecture/tests/core/services/local-storage-service-impl.test.ts +108 -0
- package/templates/react-native/expo-clean-architecture/tests/core/services/monitoring-service.test.ts +74 -0
- package/templates/react-native/expo-clean-architecture/tests/core/services/network-service.test.ts +117 -0
- package/templates/react-native/expo-clean-architecture/tests/features/auth/presentation/hooks/use-session.test.ts +69 -0
- package/templates/react-native/expo-clean-architecture/tests/features/favorites/data/datasources/favorites-datasource.test.ts +69 -0
- package/templates/react-native/expo-clean-architecture/tests/features/favorites/data/repositories/favorites-repository-impl.test.ts +124 -0
- package/templates/react-native/expo-clean-architecture/tests/features/favorites/domain/usecases/add-to-favorites-usecase.test.ts +54 -0
- package/templates/react-native/expo-clean-architecture/tests/features/favorites/domain/usecases/clear-favorites-usecase.test.ts +44 -0
- package/templates/react-native/expo-clean-architecture/tests/features/favorites/domain/usecases/get-favorites-usecase.test.ts +74 -0
- package/templates/react-native/expo-clean-architecture/tests/features/favorites/domain/usecases/remove-from-favorites-usecase.test.ts +52 -0
- package/templates/react-native/expo-clean-architecture/tests/setup.ts +9 -0
- package/templates/react-native/expo-clean-architecture/tsconfig.json +20 -0
package/bin/cli.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Point d'entrée principal du CLI
|
|
4
|
+
* Configure et lance les commandes disponibles
|
|
5
|
+
*/
|
|
2
6
|
import yargs from "yargs/yargs";
|
|
3
7
|
import { hideBin } from "yargs/helpers";
|
|
8
|
+
import { createProjectHandler } from "./commands/create-project.js";
|
|
9
|
+
import { translateHandler } from "./commands/translate.js";
|
|
4
10
|
|
|
5
11
|
yargs(hideBin(process.argv))
|
|
6
12
|
.command(
|
|
7
13
|
"create-project",
|
|
8
14
|
"Crée un nouveau projet",
|
|
9
15
|
(yargs) => {
|
|
10
|
-
return yargs
|
|
11
|
-
describe: "Nom du projet",
|
|
12
|
-
type: "string",
|
|
13
|
-
demandOption: true,
|
|
14
|
-
});
|
|
16
|
+
return yargs;
|
|
15
17
|
},
|
|
16
|
-
|
|
17
|
-
console.log(`Création du projet : ${argv.name}`);
|
|
18
|
-
// Logique de création de projet ici
|
|
19
|
-
}
|
|
18
|
+
createProjectHandler
|
|
20
19
|
)
|
|
21
20
|
.command(
|
|
22
21
|
"translate",
|
|
@@ -28,10 +27,7 @@ yargs(hideBin(process.argv))
|
|
|
28
27
|
demandOption: true,
|
|
29
28
|
});
|
|
30
29
|
},
|
|
31
|
-
|
|
32
|
-
console.log(`Gestion des traductions pour : ${argv.lang}`);
|
|
33
|
-
// Logique de gestion des traductions ici
|
|
34
|
-
}
|
|
30
|
+
translateHandler
|
|
35
31
|
)
|
|
36
32
|
.demandCommand(1, "Vous devez spécifier une commande")
|
|
37
33
|
.help().argv;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commande pour créer un nouveau projet à partir d'un template
|
|
3
|
+
*/
|
|
4
|
+
import inquirer from "inquirer";
|
|
5
|
+
import fs from "fs-extra";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
import { dirname } from "path";
|
|
9
|
+
import { TEMPLATES } from "../config/templates.js";
|
|
10
|
+
import { generateSlug, generateReplacements } from "../utils/project-utils.js";
|
|
11
|
+
import { processDirectory, replacePlaceholdersInFile } from "../utils/file-utils.js";
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Copie un template et remplace les placeholders
|
|
18
|
+
* @param {string} templatePath - Le chemin relatif du template
|
|
19
|
+
* @param {string} projectName - Le nom du projet
|
|
20
|
+
* @param {string} targetPath - Le chemin de destination
|
|
21
|
+
*/
|
|
22
|
+
async function copyTemplate(templatePath, projectName, targetPath) {
|
|
23
|
+
const sourcePath = path.join(__dirname, "..", "..", "templates", templatePath);
|
|
24
|
+
|
|
25
|
+
// Vérifier que le template existe
|
|
26
|
+
if (!(await fs.pathExists(sourcePath))) {
|
|
27
|
+
throw new Error(`Le template ${templatePath} n'existe pas`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Vérifier que le répertoire cible n'existe pas déjà
|
|
31
|
+
if (await fs.pathExists(targetPath)) {
|
|
32
|
+
throw new Error(`Le répertoire ${targetPath} existe déjà`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Copier le template
|
|
36
|
+
await fs.copy(sourcePath, targetPath);
|
|
37
|
+
|
|
38
|
+
// Préparer les replacements
|
|
39
|
+
const replacements = generateReplacements(projectName);
|
|
40
|
+
|
|
41
|
+
// Remplacer les placeholders dans tous les fichiers
|
|
42
|
+
const files = await fs.readdir(targetPath, { withFileTypes: true });
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
const filePath = path.join(targetPath, file.name);
|
|
45
|
+
if (file.isDirectory()) {
|
|
46
|
+
await processDirectory(filePath, replacements);
|
|
47
|
+
} else {
|
|
48
|
+
await replacePlaceholdersInFile(filePath, replacements);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Handler de la commande create-project
|
|
55
|
+
*/
|
|
56
|
+
export async function createProjectHandler() {
|
|
57
|
+
try {
|
|
58
|
+
// Prompt pour le type de projet
|
|
59
|
+
const { projectType } = await inquirer.prompt([
|
|
60
|
+
{
|
|
61
|
+
type: "list",
|
|
62
|
+
name: "projectType",
|
|
63
|
+
message: "Quel type de projet voulez-vous créer ?",
|
|
64
|
+
choices: Object.entries(TEMPLATES).map(([key, template]) => ({
|
|
65
|
+
name: template.name,
|
|
66
|
+
value: key,
|
|
67
|
+
})),
|
|
68
|
+
},
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
// Prompt pour le nom du projet
|
|
72
|
+
const { projectName } = await inquirer.prompt([
|
|
73
|
+
{
|
|
74
|
+
type: "input",
|
|
75
|
+
name: "projectName",
|
|
76
|
+
message: "Quel est le nom de votre projet ?",
|
|
77
|
+
validate: (input) => {
|
|
78
|
+
if (!input || input.trim().length === 0) {
|
|
79
|
+
return "Le nom du projet ne peut pas être vide";
|
|
80
|
+
}
|
|
81
|
+
if (!/^[a-zA-Z0-9\s-_]+$/.test(input)) {
|
|
82
|
+
return "Le nom du projet ne peut contenir que des lettres, chiffres, espaces, tirets et underscores";
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
const template = TEMPLATES[projectType];
|
|
90
|
+
const targetPath = path.join(process.cwd(), generateSlug(projectName));
|
|
91
|
+
|
|
92
|
+
console.log(`\nCréation du projet "${projectName}" avec le template ${template.name}...`);
|
|
93
|
+
console.log(`Répertoire cible : ${targetPath}\n`);
|
|
94
|
+
|
|
95
|
+
await copyTemplate(template.path, projectName, targetPath);
|
|
96
|
+
|
|
97
|
+
console.log(`✅ Projet créé avec succès dans ${targetPath}`);
|
|
98
|
+
console.log(`\nPour démarrer :`);
|
|
99
|
+
console.log(` cd ${path.basename(targetPath)}`);
|
|
100
|
+
console.log(` npm install`);
|
|
101
|
+
console.log(` npm start\n`);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error(`❌ Erreur lors de la création du projet : ${error.message}`);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commande pour gérer les traductions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Handler de la commande translate
|
|
7
|
+
* @param {Object} argv - Arguments de la commande
|
|
8
|
+
*/
|
|
9
|
+
export function translateHandler(argv) {
|
|
10
|
+
console.log(`Gestion des traductions pour : ${argv.lang}`);
|
|
11
|
+
// Logique de gestion des traductions ici
|
|
12
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilitaires pour la gestion des fichiers et le remplacement de placeholders
|
|
3
|
+
*/
|
|
4
|
+
import fs from "fs-extra";
|
|
5
|
+
import path from "path";
|
|
6
|
+
|
|
7
|
+
// Extensions de fichiers binaires à ignorer lors du remplacement de placeholders
|
|
8
|
+
const BINARY_EXTENSIONS = [
|
|
9
|
+
".png",
|
|
10
|
+
".jpg",
|
|
11
|
+
".jpeg",
|
|
12
|
+
".gif",
|
|
13
|
+
".ico",
|
|
14
|
+
".svg",
|
|
15
|
+
".ttf",
|
|
16
|
+
".woff",
|
|
17
|
+
".woff2",
|
|
18
|
+
".eot",
|
|
19
|
+
".otf",
|
|
20
|
+
".pdf",
|
|
21
|
+
".zip",
|
|
22
|
+
".tar",
|
|
23
|
+
".gz",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Vérifie si un fichier est binaire selon son extension
|
|
28
|
+
* @param {string} filePath - Le chemin du fichier
|
|
29
|
+
* @returns {boolean} True si le fichier est binaire
|
|
30
|
+
*/
|
|
31
|
+
export function isBinaryFile(filePath) {
|
|
32
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
33
|
+
return BINARY_EXTENSIONS.includes(ext);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Remplace les placeholders dans un fichier texte
|
|
38
|
+
* @param {string} filePath - Le chemin du fichier
|
|
39
|
+
* @param {Object} replacements - Objet contenant les replacements (clé: valeur)
|
|
40
|
+
*/
|
|
41
|
+
export async function replacePlaceholdersInFile(filePath, replacements) {
|
|
42
|
+
// Ignorer les fichiers binaires
|
|
43
|
+
if (isBinaryFile(filePath)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
49
|
+
let newContent = content;
|
|
50
|
+
|
|
51
|
+
for (const [key, value] of Object.entries(replacements)) {
|
|
52
|
+
const regex = new RegExp(`{{${key}}}`, "g");
|
|
53
|
+
newContent = newContent.replace(regex, value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (newContent !== content) {
|
|
57
|
+
await fs.writeFile(filePath, newContent, "utf-8");
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
// Ignorer les erreurs silencieusement pour les fichiers non textuels
|
|
61
|
+
if (error.code !== "EISDIR") {
|
|
62
|
+
// Ne rien faire pour les fichiers qui ne peuvent pas être lus comme texte
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Traite récursivement un répertoire pour remplacer les placeholders
|
|
69
|
+
* @param {string} dirPath - Le chemin du répertoire
|
|
70
|
+
* @param {Object} replacements - Objet contenant les replacements
|
|
71
|
+
*/
|
|
72
|
+
export async function processDirectory(dirPath, replacements) {
|
|
73
|
+
const files = await fs.readdir(dirPath, { withFileTypes: true });
|
|
74
|
+
|
|
75
|
+
for (const file of files) {
|
|
76
|
+
const filePath = path.join(dirPath, file.name);
|
|
77
|
+
|
|
78
|
+
if (file.isDirectory()) {
|
|
79
|
+
await processDirectory(filePath, replacements);
|
|
80
|
+
} else {
|
|
81
|
+
await replacePlaceholdersInFile(filePath, replacements);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilitaires pour la génération de noms et identifiants de projet
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Génère un slug à partir d'un nom de projet
|
|
7
|
+
* @param {string} name - Le nom du projet
|
|
8
|
+
* @returns {string} Le slug généré
|
|
9
|
+
*/
|
|
10
|
+
export function generateSlug(name) {
|
|
11
|
+
return name
|
|
12
|
+
.toLowerCase()
|
|
13
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
14
|
+
.replace(/^-+|-+$/g, "");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Génère un bundle identifier iOS à partir d'un slug
|
|
19
|
+
* @param {string} slug - Le slug du projet
|
|
20
|
+
* @returns {string} Le bundle identifier iOS (ex: com.monapp)
|
|
21
|
+
*/
|
|
22
|
+
export function generateIOSBundleId(slug) {
|
|
23
|
+
return `com.${slug.replace(/-/g, "")}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Génère un package Android à partir d'un slug
|
|
28
|
+
* @param {string} slug - Le slug du projet
|
|
29
|
+
* @returns {string} Le package Android (ex: com.mon.app)
|
|
30
|
+
*/
|
|
31
|
+
export function generateAndroidPackage(slug) {
|
|
32
|
+
return `com.${slug.replace(/-/g, ".")}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Génère tous les replacements pour un projet
|
|
37
|
+
* @param {string} projectName - Le nom du projet
|
|
38
|
+
* @returns {Object} Objet contenant tous les replacements
|
|
39
|
+
*/
|
|
40
|
+
export function generateReplacements(projectName) {
|
|
41
|
+
const slug = generateSlug(projectName);
|
|
42
|
+
return {
|
|
43
|
+
APP_NAME: projectName,
|
|
44
|
+
APP_SLUG: slug,
|
|
45
|
+
APP_SCHEME: slug,
|
|
46
|
+
IOS_BUNDLE_ID: generateIOSBundleId(slug),
|
|
47
|
+
ANDROID_PACKAGE: generateAndroidPackage(slug),
|
|
48
|
+
};
|
|
49
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nico-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Une suite d'outils dédiés à mes projets",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
"templates"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"yargs": "^18.0.0"
|
|
25
|
+
"yargs": "^18.0.0",
|
|
26
|
+
"inquirer": "^9.2.15",
|
|
27
|
+
"fs-extra": "^11.2.0"
|
|
26
28
|
},
|
|
27
29
|
"type": "module"
|
|
28
30
|
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Template Socle React Native + Expo
|
|
2
|
+
|
|
3
|
+
Ce template fournit une base pour créer des applications React Native avec Expo en suivant les principes de **Clean Architecture**.
|
|
4
|
+
|
|
5
|
+
## 🚀 Utilisation
|
|
6
|
+
|
|
7
|
+
### Créer un nouveau projet avec ce template
|
|
8
|
+
|
|
9
|
+
**Option 1 : Depuis un chemin local (pointant vers le dossier template)**
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx create-expo-app MonApp --template /chemin/vers/socle-react-native-expo/template
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Option 2 : Depuis le projet racine (si publié sur NPM)**
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx create-expo-app MonApp --template expo-template-socle-react-native
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Option 3 : Depuis un dépôt Git**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx create-expo-app MonApp --template https://github.com/votre-org/expo-template-socle
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
> **Note importante** : Si vous utilisez un chemin local, vous devez pointer vers le dossier `template/` et non vers le projet racine, sinon le dossier `template/` sera copié tel quel dans le nouveau projet.
|
|
28
|
+
|
|
29
|
+
## 📋 Configuration requise
|
|
30
|
+
|
|
31
|
+
Après la création du projet, vous devrez effectuer les étapes suivantes :
|
|
32
|
+
|
|
33
|
+
### 1. Installer les dépendances
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. Configurer les identifiants de l'application
|
|
40
|
+
|
|
41
|
+
Modifiez le fichier `app.config.ts` pour personnaliser :
|
|
42
|
+
|
|
43
|
+
- `name` : Nom d'affichage de l'application
|
|
44
|
+
- `slug` : Identifiant unique de l'application
|
|
45
|
+
- `scheme` : Schéma de deep linking
|
|
46
|
+
- `ios.bundleIdentifier` : Identifiant du bundle iOS (ex: `com.votre-org.monapp`)
|
|
47
|
+
- `android.package` : Package Android (ex: `com.votre-org.monapp`)
|
|
48
|
+
|
|
49
|
+
### 3. Configurer Firebase (optionnel)
|
|
50
|
+
|
|
51
|
+
Si vous souhaitez utiliser Firebase :
|
|
52
|
+
|
|
53
|
+
1. Créez un projet Firebase dans la [console Firebase](https://console.firebase.google.com/)
|
|
54
|
+
2. Téléchargez les fichiers de configuration :
|
|
55
|
+
- `GoogleService-Info.plist` pour iOS → placez-le dans `assets/config/`
|
|
56
|
+
- `google-services.json` pour Android → placez-le dans `assets/config/`
|
|
57
|
+
3. Décommentez les lignes suivantes dans `app.config.ts` :
|
|
58
|
+
```typescript
|
|
59
|
+
// Dans la section ios:
|
|
60
|
+
googleServicesFile: "./assets/config/GoogleService-Info.plist",
|
|
61
|
+
|
|
62
|
+
// Dans la section android:
|
|
63
|
+
googleServicesFile: "./assets/config/google-services.json",
|
|
64
|
+
|
|
65
|
+
// Dans la section plugins:
|
|
66
|
+
"@react-native-firebase/app",
|
|
67
|
+
"@react-native-firebase/crashlytics",
|
|
68
|
+
```
|
|
69
|
+
4. Pour iOS, installez les pods :
|
|
70
|
+
```bash
|
|
71
|
+
cd ios && pod install && cd ..
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 4. Configurer les variables d'environnement
|
|
75
|
+
|
|
76
|
+
Créez un fichier `.env` à la racine du projet pour vos variables d'environnement :
|
|
77
|
+
|
|
78
|
+
```env
|
|
79
|
+
EXPO_PUBLIC_TMDB_TOKEN=votre_token_ici
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 5. Personnaliser les assets
|
|
83
|
+
|
|
84
|
+
Remplacez les images dans `assets/images/` :
|
|
85
|
+
- `icon.png` : Icône de l'application
|
|
86
|
+
- `adaptive-icon.png` : Icône adaptative Android
|
|
87
|
+
- `splash-icon.png` : Icône du splash screen
|
|
88
|
+
- `favicon.png` : Favicon web
|
|
89
|
+
|
|
90
|
+
## 🏗 Architecture
|
|
91
|
+
|
|
92
|
+
Ce template suit les principes de **Clean Architecture** avec une approche **feature-based**.
|
|
93
|
+
|
|
94
|
+
### Structure des features
|
|
95
|
+
|
|
96
|
+
Chaque feature est divisée en 3 couches :
|
|
97
|
+
|
|
98
|
+
- **`data`** : Récupération des données (API, stockage local)
|
|
99
|
+
- **`domain`** : Logique métier (entités, use cases, repositories)
|
|
100
|
+
- **`presentation`** : Interface utilisateur (composants, hooks)
|
|
101
|
+
|
|
102
|
+
Pour plus de détails, consultez la [documentation technique](docs/01-architecture.md).
|
|
103
|
+
|
|
104
|
+
## 📚 Documentation
|
|
105
|
+
|
|
106
|
+
- [Documentation technique](docs/00-introduction.md)
|
|
107
|
+
- [Architecture](docs/01-architecture.md)
|
|
108
|
+
|
|
109
|
+
## 🛠 Scripts disponibles
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Démarrer l'application en mode développement
|
|
113
|
+
npm start
|
|
114
|
+
|
|
115
|
+
# Lancer sur iOS
|
|
116
|
+
npm run ios
|
|
117
|
+
|
|
118
|
+
# Lancer sur Android
|
|
119
|
+
npm run android
|
|
120
|
+
|
|
121
|
+
# Lancer sur le web
|
|
122
|
+
npm run web
|
|
123
|
+
|
|
124
|
+
# Lancer les tests
|
|
125
|
+
npm test
|
|
126
|
+
|
|
127
|
+
# Lancer le linter
|
|
128
|
+
npm run lint
|
|
129
|
+
|
|
130
|
+
# Nettoyer les dossiers iOS/Android
|
|
131
|
+
npm run clean
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## 📦 Stack technique
|
|
135
|
+
|
|
136
|
+
- **React Native** + **Expo** : Framework mobile
|
|
137
|
+
- **Expo Router** : Navigation file-based
|
|
138
|
+
- **TypeScript** : Typage statique
|
|
139
|
+
- **@tanstack/react-query** : Gestion d'état serveur
|
|
140
|
+
- **zustand** : Gestion d'état applicatif
|
|
141
|
+
- **Inversify** : Injection de dépendances
|
|
142
|
+
- **react-i18next** : Internationalisation
|
|
143
|
+
|
|
144
|
+
## 🔗 Liens utiles
|
|
145
|
+
|
|
146
|
+
- [Documentation Expo](https://docs.expo.dev/)
|
|
147
|
+
- [Documentation React Native](https://reactnative.dev/)
|
|
148
|
+
- [Expo Router](https://docs.expo.dev/router/introduction/)
|
|
149
|
+
|
|
150
|
+
## 📝 Notes
|
|
151
|
+
|
|
152
|
+
- Les dossiers `ios/` et `android/` sont générés automatiquement et ne doivent pas être versionnés
|
|
153
|
+
- Le template inclut une configuration de base pour les tests avec Jest
|
|
154
|
+
- L'internationalisation est configurée avec `react-i18next` (français par défaut)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import "ts-node/register";
|
|
2
|
+
import { ExpoConfig } from "expo/config";
|
|
3
|
+
|
|
4
|
+
const config: ExpoConfig = {
|
|
5
|
+
name: "{{APP_NAME}}",
|
|
6
|
+
slug: "{{APP_SLUG}}",
|
|
7
|
+
version: "1.0.0",
|
|
8
|
+
orientation: "portrait",
|
|
9
|
+
icon: "./assets/images/icon.png",
|
|
10
|
+
scheme: "{{APP_SCHEME}}",
|
|
11
|
+
userInterfaceStyle: "automatic",
|
|
12
|
+
newArchEnabled: true,
|
|
13
|
+
ios: {
|
|
14
|
+
supportsTablet: true,
|
|
15
|
+
// Décommenter et configurer si vous utilisez Firebase
|
|
16
|
+
// googleServicesFile: "./assets/config/GoogleService-Info.plist",
|
|
17
|
+
bundleIdentifier: "{{IOS_BUNDLE_ID}}",
|
|
18
|
+
},
|
|
19
|
+
android: {
|
|
20
|
+
adaptiveIcon: {
|
|
21
|
+
foregroundImage: "./assets/images/adaptive-icon.png",
|
|
22
|
+
backgroundColor: "#ffffff",
|
|
23
|
+
},
|
|
24
|
+
// Décommenter et configurer si vous utilisez Firebase
|
|
25
|
+
// googleServicesFile: "./assets/config/google-services.json",
|
|
26
|
+
package: "{{ANDROID_PACKAGE}}",
|
|
27
|
+
},
|
|
28
|
+
web: {
|
|
29
|
+
bundler: "metro",
|
|
30
|
+
output: "static",
|
|
31
|
+
favicon: "./assets/images/favicon.png",
|
|
32
|
+
},
|
|
33
|
+
plugins: [
|
|
34
|
+
"expo-router",
|
|
35
|
+
[
|
|
36
|
+
"expo-splash-screen",
|
|
37
|
+
{
|
|
38
|
+
image: "./assets/images/splash-icon.png",
|
|
39
|
+
imageWidth: 200,
|
|
40
|
+
resizeMode: "contain",
|
|
41
|
+
backgroundColor: "#ffffff",
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
// Décommenter si vous utilisez Firebase
|
|
45
|
+
// "@react-native-firebase/app",
|
|
46
|
+
// "@react-native-firebase/crashlytics",
|
|
47
|
+
[
|
|
48
|
+
"expo-build-properties",
|
|
49
|
+
{
|
|
50
|
+
ios: {
|
|
51
|
+
useFrameworks: "static",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
],
|
|
56
|
+
experiments: {
|
|
57
|
+
typedRoutes: true,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default config;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module.exports = function (api) {
|
|
2
|
+
api.cache(true);
|
|
3
|
+
return {
|
|
4
|
+
plugins: [
|
|
5
|
+
"babel-plugin-transform-typescript-metadata",
|
|
6
|
+
["@babel/plugin-proposal-decorators", { legacy: true }],
|
|
7
|
+
["@babel/plugin-proposal-class-properties", { loose: true }],
|
|
8
|
+
],
|
|
9
|
+
presets: ["babel-preset-expo"],
|
|
10
|
+
};
|
|
11
|
+
};
|