Initial commit

This commit is contained in:
2026-06-29 15:47:16 +02:00
commit b9d2db7ac9
7 changed files with 280 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false
+2
View File
@@ -0,0 +1,2 @@
node_modules
dist
+6
View File
@@ -0,0 +1,6 @@
{
"printWidth": 100,
"tabWidth": 4,
"singleQuote": true,
"trailingComma": "es5"
}
+55
View File
@@ -0,0 +1,55 @@
{
"name": "expo-kit",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "expo-kit",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"child_process": "^1.0.2",
"commander": "^15.0.0"
},
"bin": {
"expo-kit": "dist/index.js"
},
"devDependencies": {
"@types/node": "^26.0.1"
}
},
"node_modules/@types/node": {
"version": "26.0.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.1.tgz",
"integrity": "sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~8.3.0"
}
},
"node_modules/child_process": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz",
"integrity": "sha512-Wmza/JzL0SiWz7kl6MhIKT5ceIlnFPJX+lwUGj7Clhy5MMldsSoJR0+uvRzOS5Kv45Mq7t1PoE8TsOA9bzvb6g==",
"license": "ISC"
},
"node_modules/commander": {
"version": "15.0.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz",
"integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==",
"license": "MIT",
"engines": {
"node": ">=22.12.0"
}
},
"node_modules/undici-types": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
"integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
"dev": true,
"license": "MIT"
}
}
}
+26
View File
@@ -0,0 +1,26 @@
{
"name": "expo-kit",
"version": "1.0.0",
"description": "Expo starter kit CLI",
"repository": {
"type": "git",
"url": "ssh://git@git.justzoe101.nl:2222/Expo-Starter-Kit/CLI.git"
},
"license": "ISC",
"author": "JustZoe101",
"type": "commonjs",
"main": "index.js",
"scripts": {
"start": "npm run clean; npm run build; node ./dist/index.js",
"build": "tsc",
"clean": "rm -rf ./dist"
},
"bin": "./dist/index.js",
"dependencies": {
"child_process": "^1.0.2",
"commander": "^15.0.0"
},
"devDependencies": {
"@types/node": "^26.0.1"
}
}
+133
View File
@@ -0,0 +1,133 @@
import { Command, program } from 'commander';
import { exec } from 'child_process';
import { promisify } from 'util';
import fs from 'fs';
const execAsync = promisify(exec);
program.name('Expo kit').description('Expo framework for multiple plugins').version('1.0.0');
program
.command('new')
.argument('<name>', 'Project name')
.option('--reactnavigation', 'Adds reactnavigation to project')
.option('--nativewind', 'Adds nativewind to project')
.option('--i18next', 'Adds i18next to project')
.action(createProject);
async function createProject(name: string, ...args: any[]) {
const dir = `${__dirname}/${name}`;
const options: {
reactnavigation: boolean;
nativewind: boolean;
i18next: boolean;
} = args[0];
console.log('📦 Installing starter template...');
await execAsync(
`git clone https://git.justzoe101.nl/Expo-Starter-Kit/Template.git ${dir} --depth 1`
);
combineAppJson(dir, {
appJson: {
expo: {
name,
slug: name.toLowerCase(),
},
},
});
await execAsync('npm i', {
cwd: dir,
});
console.log('✅ Starter template installed!\r\n');
if (options.reactnavigation) {
console.log('📦 Installing reactnavigation dependencies...');
const plugin = require(`${dir}/plugins/reactnavigation/plugin.json`);
await _installDependencies(dir, plugin);
console.log('✅ Reactnavigation installed!\r\n');
}
if (options.nativewind) {
console.log('📦 Installing nativewind dependencies...');
const plugin = require(`${dir}/plugins/nativewind/plugin.json`);
await _installDependencies(dir, plugin);
console.log('✅ Nativewind installed!\r\n');
}
if (options.i18next) {
console.log('📦 Installing i18next dependencies...');
const plugin = require(`${dir}/plugins/i18next/plugin.json`);
await _installDependencies(dir, plugin);
combineAppJson(dir, plugin);
console.log('✅ I18next installed!\r\n');
}
}
async function _installDependencies(dir: string, plugin: Plugin) {
const keys = Object.keys(plugin);
if (keys.includes('dependencies')) {
let dependencies: any = Object.entries(plugin.dependencies!);
dependencies = dependencies.flatMap((d: any[]) => `${d[0]}@${d[1]}`).join(' ');
await execAsync(`npm i ${dependencies}`, {
cwd: dir,
});
}
if (keys.includes('devDependencies')) {
let dependencies: any = Object.entries(plugin.devDependencies!);
dependencies = dependencies.flatMap((d: any[]) => `${d[0]}@${d[1]}`).join(' ');
await execAsync(`npm i ${dependencies} --save-dev`, {
cwd: dir,
});
}
if (keys.includes('expoDependencies')) {
let dependencies: any = plugin.expoDependencies!.join(' ');
await execAsync(`npx expo install ${dependencies}`, {
cwd: dir,
});
}
}
function combineAppJson(dir: string, plugin: Plugin) {
fs.writeFileSync(
`${dir}/app.json`,
JSON.stringify(deepMerge(require(`${dir}/app.json`), plugin.appJson), null, 4),
'utf8'
);
}
function deepMerge(target: any, source: any) {
if (Array.isArray(target) && Array.isArray(source)) {
return source; // or target.concat(source) if that's what you want
}
if (target && source && typeof target === 'object' && typeof source === 'object') {
const result = { ...target };
for (const key of Object.keys(source)) {
result[key] = key in target ? deepMerge(target[key], source[key]) : source[key];
}
return result;
}
return source;
}
type Plugin = {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
expoDependencies?: string[];
appJson?: object;
};
program.parse();
+46
View File
@@ -0,0 +1,46 @@
{
// Visit https://aka.ms/tsconfig to read more about this file
"compilerOptions": {
// File Layout
"rootDir": "./src",
"outDir": "./dist",
// Environment Settings
// See also https://aka.ms/tsconfig/module
"module": "nodenext",
"target": "esnext",
"types": ["node"],
// For nodejs:
// "lib": ["esnext"],
// "types": ["node"],
// and npm install -D @types/node
// Other Outputs
"sourceMap": true,
"declaration": true,
"declarationMap": true,
// Stricter Typechecking Options
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
// Style Options
// "noImplicitReturns": true,
// "noImplicitOverride": true,
// "noUnusedLocals": true,
// "noUnusedParameters": true,
// "noFallthroughCasesInSwitch": true,
// "noPropertyAccessFromIndexSignature": true,
// Recommended Options
"strict": true,
"jsx": "react-jsx",
"verbatimModuleSyntax": false,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true,
"resolveJsonModule": true
},
"include": ["./src/**/*.json", "./src/**/*.ts"]
}