#!/usr/bin/env node
import fs from 'fs';
import path from 'path';
const args = process.argv.slice(2);
function getArg(name) {
const idx = args.indexOf(name);
return idx !== -1 ? args[idx + 1] : null;
}
function toKebab(str) {
return str
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
.replace(/_/g, '-')
.toLowerCase();
}
const moduleName = getArg('-name');
const moduleNum = getArg('-num');
if (!moduleName || !moduleNum) {
console.log('Используй: npm run add-module -- -name settings -num 10');
process.exit(1);
}
const root = process.cwd();
const folderName = toKebab(moduleName);
const modulesDir = path.join(root, 'src/modules');
const moduleDir = path.join(modulesDir, folderName);
if (fs.existsSync(moduleDir)) {
console.log('Модуль уже существует');
process.exit(1);
}
const pascal =
moduleName
.replace(/(^\w|[A-Z]|\b\w)/g, c => c.toUpperCase())
.replace(/[-_]/g, '');
// ---------- helpers ----------
const EOL = '\n';
function write(file, content) {
fs.mkdirSync(path.dirname(file), { recursive: true });
fs.writeFileSync(file, content.trimStart().replace(/\r?\n/g, EOL));
}
// ---------- configs ----------
const viteConfig = `
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import path from 'node:path';
export default defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'src/index.ts'),
name: '${pascal}',
formats: ['es', 'cjs'],
fileName: (format) => \`index.\${format}.js\`
},
rollupOptions: {
external: (id) => id.startsWith('@itprom/') || ['vue', 'pinia', 'vue-router', 'element-plus'].includes(id),
output: {
preserveModules: false
}
},
outDir: 'dist'
},
resolve: {
alias: {
'@': path.resolve(__dirname, '../../')
}
},
plugins: [
vue(),
vueJsx()
]
});
`;
const tsconfig = `
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"verbatimModuleSyntax": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "preserve",
"jsxImportSource": "vue",
"types": [
"vite/client",
"node"
],
"declaration": true,
"outDir": "dist",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true
},
"include": [
"**/*.ts",
"**/*.tsx",
"**/*.vue",
"**/*.d.ts"
]
}
`;
const tsconfigBuild = `
{
"extends": "./tsconfig.json",
"compilerOptions": {
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "dist",
"noEmit": false,
"paths": {
"@itprom/*": [
"../src/modules/*/src/index.d.ts"
]
}
},
"include": [
"src/**/*"
],
"exclude": [
"vite.config.ts"
]
}
`;
const pkg = `
{
"name": "@itprom/${folderName}",
"version": "1.0.0",
"main": "dist/index.cjs.js",
"module": "dist/index.es.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "vite build && vue-tsc -p tsconfig.build.json"
},
"peerDependencies": {
"@itprom/core": "^1.0.0",
"@itprom/core-components": "^1.0.0",
"vue": "^3.5.27"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.es.js",
"require": "./dist/index.cjs.js"
}
}
}
`;
// ---------- src files ----------
const moduleInfo = `
import { type ModuleInfo } from '@itprom/core';
export const moduleInfo: ModuleInfo = {
name: '${moduleName}',
num: '${moduleNum}',
component: () => import('./components/${pascal}Component.vue')
};
`;
const indexTs = `
export * from './classes/${pascal}';
export { } from './classes/${pascal}Service';
export { default as ${pascal}Component } from './components/${pascal}Component.vue';
export { moduleInfo } from './moduleInfo';
`;
const componentVue = `
`;
const classTs = `
export class ${pascal} {
}
`;
const serviceTs = `
export class ${pascal}Service {
}
`;
// ---------- write ----------
write(path.join(moduleDir, 'vite.config.ts'), viteConfig);
write(path.join(moduleDir, 'tsconfig.json'), tsconfig);
write(path.join(moduleDir, 'tsconfig.build.json'), tsconfigBuild);
write(path.join(moduleDir, 'package.json'), pkg);
write(path.join(moduleDir, 'src/components', `${pascal}Component.vue`), componentVue);
write(path.join(moduleDir, 'src/classes', `${pascal}.ts`), classTs);
write(path.join(moduleDir, 'src/classes', `${pascal}Service.ts`), serviceTs);
write(path.join(moduleDir, 'src/moduleInfo.ts'), moduleInfo);
write(path.join(moduleDir, 'src/index.ts'), indexTs);
// ---------- update modules.json ----------
const modulesJsonPath = path.join(root, 'scripts/modules.json');
if (fs.existsSync(modulesJsonPath)) {
const list = JSON.parse(fs.readFileSync(modulesJsonPath, 'utf8'));
if (!list.includes(folderName)) {
list.push(folderName);
fs.writeFileSync(modulesJsonPath, JSON.stringify(list, null, 2));
}
}
// ---------- update root package.json ----------
const rootPkgPath = path.join(root, 'package.json');
if (fs.existsSync(rootPkgPath)) {
const rootPkg = JSON.parse(fs.readFileSync(rootPkgPath, 'utf8'));
rootPkg.dependencies ??= {};
const depName = `@itprom/${folderName}`;
if (!rootPkg.dependencies[depName]) {
rootPkg.dependencies[depName] = 'workspace:*';
}
fs.writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2));
}
console.log(`✅ Модуль ${moduleName} создан`);