#!/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" }, "./*": { "types": "./dist/*.d.ts", "import": "./dist/*.js", "require": "./dist/*.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} создан`);