easybuild-nox 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.
@@ -0,0 +1,407 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ const FRAMEWORKS = {
5
+ // Backend frameworks
6
+ express: { type: 'backend', config: 'express' },
7
+ fastify: { type: 'backend', config: 'fastify' },
8
+ koa: { type: 'backend', config: 'koa' },
9
+ hapi: { type: 'backend', config: 'hapi' },
10
+ nestjs: { type: 'backend', config: 'nest' },
11
+ adonis: { type: 'backend', config: 'adonis' },
12
+ strapi: { type: 'backend', config: 'strapi' },
13
+ mikroorm: { type: 'backend', config: 'mikroorm' },
14
+ typeorm: { type: 'backend', config: 'typeorm' },
15
+ prisma: { type: 'backend', config: 'prisma' },
16
+ hono: { type: 'backend', config: 'hono' },
17
+ trpc: { type: 'backend', config: 'trpc' },
18
+ graphql: { type: 'backend', config: 'graphql' },
19
+ socketio: { type: 'backend', config: 'socketio' },
20
+
21
+ // Frontend frameworks
22
+ react: { type: 'frontend', config: 'react' },
23
+ vue: { type: 'frontend', config: 'vue' },
24
+ angular: { type: 'frontend', config: 'angular' },
25
+ svelte: { type: 'frontend', config: 'svelte' },
26
+ solid: { type: 'frontend', config: 'solid' },
27
+ preact: { type: 'frontend', config: 'preact' },
28
+ lit: { type: 'frontend', config: 'lit' },
29
+ alpine: { type: 'frontend', config: 'alpine' },
30
+ htmx: { type: 'frontend', config: 'htmx' },
31
+ stimulus: { type: 'frontend', config: 'stimulus' },
32
+ mithril: { type: 'frontend', config: 'mithril' },
33
+ inferno: { type: 'frontend', config: 'inferno' },
34
+ petitevue: { type: 'frontend', config: 'petitevue' },
35
+
36
+ // Full-stack frameworks
37
+ nextjs: { type: 'fullstack', config: 'next' },
38
+ nuxt: { type: 'fullstack', config: 'nuxt' },
39
+ remix: { type: 'fullstack', config: 'remix' },
40
+ gatsby: { type: 'fullstack', config: 'gatsby' },
41
+ astro: { type: 'fullstack', config: 'astro' },
42
+ sveltekit: { type: 'fullstack', config: 'sveltekit' },
43
+ solidstart: { type: 'fullstack', config: 'solidstart' },
44
+ analog: { type: 'fullstack', config: 'analog' },
45
+ qwik: { type: 'fullstack', config: 'qwik' },
46
+ fresh: { type: 'fullstack', config: 'fresh' },
47
+ hono_fullstack: { type: 'fullstack', config: 'hono' },
48
+ tanstack: { type: 'fullstack', config: 'tanstack' },
49
+ waku: { type: 'fullstack', config: 'waku' },
50
+ layr: { type: 'fullstack', config: 'layr' },
51
+
52
+ // Meta frameworks
53
+ electron: { type: 'desktop', config: 'electron' },
54
+ tauri: { type: 'desktop', config: 'tauri' },
55
+ neutralino: { type: 'desktop', config: 'neutralino' },
56
+ nwjs: { type: 'desktop', config: 'nwjs' },
57
+
58
+ // Mobile
59
+ reactnative: { type: 'mobile', config: 'reactnative' },
60
+ ionic: { type: 'mobile', config: 'ionic' },
61
+ nativescript: { type: 'mobile', config: 'nativescript' },
62
+ expo: { type: 'mobile', config: 'expo' },
63
+ reactnativeexpo: { type: 'mobile', config: 'expo' },
64
+ tamagui: { type: 'mobile', config: 'tamagui' },
65
+ nativebase: { type: 'mobile', config: 'nativebase' },
66
+
67
+ // CLI tools
68
+ commander: { type: 'cli', config: 'cli' },
69
+ yargs: { type: 'cli', config: 'cli' },
70
+ inquirer: { type: 'cli', config: 'cli' },
71
+ prompts: { type: 'cli', config: 'cli' },
72
+ meow: { type: 'cli', config: 'cli' },
73
+ cac: { type: 'cli', config: 'cli' },
74
+
75
+ // Libraries
76
+ typescript: { type: 'library', config: 'library' },
77
+ zod: { type: 'library', config: 'library' },
78
+ lodash: { type: 'library', config: 'library' },
79
+ datefns: { type: 'library', config: 'library' },
80
+ dayjs: { type: 'library', config: 'library' },
81
+ axios: { type: 'library', config: 'library' },
82
+ got: { type: 'library', config: 'library' },
83
+ ky: { type: 'library', config: 'library' },
84
+
85
+ // CMS
86
+ sanity: { type: 'cms', config: 'sanity' },
87
+ contentful: { type: 'cms', config: 'contentful' },
88
+ payload: { type: 'cms', config: 'payload' },
89
+ directus: { type: 'cms', config: 'directus' },
90
+
91
+ // Ecommerce
92
+ medusa: { type: 'ecommerce', config: 'medusa' },
93
+ saleor: { type: 'ecommerce', config: 'saleor' },
94
+ shopify: { type: 'ecommerce', config: 'shopify' },
95
+
96
+ // Database ORMs
97
+ drizzle: { type: 'database', config: 'drizzle' },
98
+ kysely: { type: 'database', config: 'kysely' },
99
+ sequelize: { type: 'database', config: 'sequelize' },
100
+ mongoose: { type: 'database', config: 'mongoose' },
101
+ };
102
+
103
+ const BUNDLERS = {
104
+ esbuild: 'esbuild',
105
+ webpack: 'webpack',
106
+ vite: 'vite',
107
+ rollup: 'rollup',
108
+ parcel: 'parcel',
109
+ swc: 'swc',
110
+ turbopack: 'turbopack',
111
+ };
112
+
113
+ class ProjectDetector {
114
+ constructor(rootDir = process.cwd()) {
115
+ this.rootDir = rootDir;
116
+ this.packageJson = null;
117
+ this.detectedFramework = null;
118
+ this.detectedBundler = null;
119
+ this.projectType = null;
120
+ }
121
+
122
+ async detect() {
123
+ await this.loadPackageJson();
124
+ await this.detectFramework();
125
+ await this.detectBundler();
126
+ await this.detectTypeScript();
127
+ await this.detectMonorepo();
128
+
129
+ return {
130
+ framework: this.detectedFramework,
131
+ bundler: this.detectedBundler,
132
+ type: this.projectType,
133
+ isTypeScript: this.isTypeScript,
134
+ isMonorepo: this.isMonorepo,
135
+ packageJson: this.packageJson,
136
+ };
137
+ }
138
+
139
+ async loadPackageJson() {
140
+ const pkgPath = path.join(this.rootDir, 'package.json');
141
+ if (await fs.pathExists(pkgPath)) {
142
+ this.packageJson = await fs.readJson(pkgPath);
143
+ }
144
+ }
145
+
146
+ async detectFramework() {
147
+ if (!this.packageJson) return;
148
+
149
+ const deps = {
150
+ ...this.packageJson.dependencies,
151
+ ...this.packageJson.devDependencies,
152
+ };
153
+
154
+ // Check for frameworks in dependencies
155
+ for (const [framework, info] of Object.entries(FRAMEWORKS)) {
156
+ const frameworkPatterns = this.getFrameworkPatterns(framework);
157
+ for (const pattern of frameworkPatterns) {
158
+ if (deps[pattern]) {
159
+ this.detectedFramework = { name: framework, ...info };
160
+ this.projectType = info.type;
161
+ return;
162
+ }
163
+ }
164
+ }
165
+
166
+ // Check for common file patterns
167
+ await this.detectByFilePatterns();
168
+ }
169
+
170
+ getFrameworkPatterns(framework) {
171
+ const patterns = {
172
+ // Backend
173
+ express: ['express'],
174
+ fastify: ['fastify', '@fastify/fastify'],
175
+ koa: ['koa'],
176
+ hapi: ['@hapi/hapi'],
177
+ nestjs: ['@nestjs/core', '@nestjs/common'],
178
+ adonis: ['@adonisjs/framework', '@adonisjs/core'],
179
+ strapi: ['@strapi/strapi'],
180
+ hono: ['hono'],
181
+ trpc: ['@trpc/server', '@trpc/client'],
182
+ graphql: ['graphql', '@graphql-js/core', 'apollo-server'],
183
+ socketio: ['socket.io'],
184
+
185
+ // Frontend
186
+ react: ['react', 'react-dom'],
187
+ vue: ['vue', 'nuxt'],
188
+ angular: ['@angular/core'],
189
+ svelte: ['svelte', '@sveltejs/kit'],
190
+ solid: ['solid-js', 'solid-start'],
191
+ preact: ['preact'],
192
+ lit: ['lit', 'lit-element'],
193
+ alpine: ['alpinejs'],
194
+ htmx: ['htmx.org'],
195
+ stimulus: ['@hotwired/stimulus'],
196
+ mithril: ['mithril'],
197
+ inferno: ['inferno'],
198
+ petitevue: ['petite-vue'],
199
+
200
+ // Full-stack
201
+ nextjs: ['next'],
202
+ nuxt: ['nuxt', '@nuxt/core'],
203
+ remix: ['@remix-run/react', '@remix-run/node'],
204
+ gatsby: ['gatsby'],
205
+ astro: ['astro'],
206
+ sveltekit: ['@sveltejs/kit'],
207
+ solidstart: ['solid-start'],
208
+ analog: ['@analogjs/core'],
209
+ qwik: ['@builder.io/qwik'],
210
+ fresh: ['fresh'],
211
+ tanstack: ['@tanstack/react-start', '@tanstack/react-router'],
212
+ waku: ['waku'],
213
+
214
+ // Desktop
215
+ electron: ['electron'],
216
+ tauri: ['@tauri-apps/api'],
217
+ nwjs: ['nw'],
218
+
219
+ // Mobile
220
+ reactnative: ['react-native'],
221
+ ionic: ['@ionic/core', '@ionic/react', '@ionic/vue', '@ionic/angular'],
222
+ expo: ['expo'],
223
+ tamagui: ['tamagui'],
224
+ nativebase: ['native-base'],
225
+
226
+ // CLI
227
+ commander: ['commander'],
228
+ yargs: ['yargs'],
229
+ inquirer: ['inquirer'],
230
+ prompts: ['prompts'],
231
+ meow: ['meow'],
232
+ cac: ['cac'],
233
+
234
+ // Libraries
235
+ zod: ['zod'],
236
+ lodash: ['lodash'],
237
+ datefns: ['date-fns'],
238
+ dayjs: ['dayjs'],
239
+ axios: ['axios'],
240
+ got: ['got'],
241
+ ky: ['ky'],
242
+
243
+ // CMS
244
+ sanity: ['@sanity/client', 'sanity'],
245
+ contentful: ['contentful'],
246
+ payload: ['payload'],
247
+ directus: ['@directus/sdk'],
248
+
249
+ // Ecommerce
250
+ medusa: ['@medusajs/medusa'],
251
+ saleor: ['@saleor/sdk'],
252
+ shopify: ['@shopify/shopify-api'],
253
+
254
+ // Database
255
+ drizzle: ['drizzle-orm', 'drizzle-kit'],
256
+ kysely: ['kysely'],
257
+ sequelize: ['sequelize'],
258
+ mongoose: ['mongoose'],
259
+ };
260
+ return patterns[framework] || [framework];
261
+ }
262
+
263
+ async detectByFilePatterns() {
264
+ const filePatterns = {
265
+ // Full-stack frameworks
266
+ 'next.config.js': 'nextjs',
267
+ 'next.config.mjs': 'nextjs',
268
+ 'next.config.ts': 'nextjs',
269
+ 'nuxt.config.js': 'nuxt',
270
+ 'nuxt.config.ts': 'nuxt',
271
+ 'nuxt.config.mjs': 'nuxt',
272
+ 'remix.config.js': 'remix',
273
+ 'remix.config.mjs': 'remix',
274
+ 'gatsby-config.js': 'gatsby',
275
+ 'gatsby-config.mjs': 'gatsby',
276
+ 'gatsby-node.js': 'gatsby',
277
+ 'svelte.config.js': 'sveltekit',
278
+ 'svelte.config.mjs': 'sveltekit',
279
+ 'astro.config.mjs': 'astro',
280
+ 'astro.config.js': 'astro',
281
+ 'astro.config.ts': 'astro',
282
+ 'solid.config.js': 'solidstart',
283
+ 'solid.config.ts': 'solidstart',
284
+ 'vite.config.ts': 'vite',
285
+ 'vite.config.js': 'vite',
286
+ 'vite.config.mjs': 'vite',
287
+ 'vite.config.mts': 'vite',
288
+ 'vue.config.js': 'vue',
289
+ 'vue.config.ts': 'vue',
290
+ 'angular.json': 'angular',
291
+ 'svelte.config.js': 'svelte',
292
+
293
+ // Backend frameworks
294
+ 'nest-cli.json': 'nestjs',
295
+ '.adonisrc.json': 'adonis',
296
+ 'strapi-server.js': 'strapi',
297
+
298
+ // Desktop
299
+ 'tauri.conf.json': 'tauri',
300
+ 'tauri.conf.json5': 'tauri',
301
+ 'electron-builder.yml': 'electron',
302
+ 'electron-builder.json': 'electron',
303
+ 'electron-builder.json5': 'electron',
304
+ 'electron.vite.config.ts': 'electron',
305
+ 'electron.vite.config.js': 'electron',
306
+ 'forge.config.js': 'electron',
307
+ 'forge.config.ts': 'electron',
308
+
309
+ // Mobile
310
+ 'app.json': 'expo',
311
+ 'expo.json': 'expo',
312
+ 'capacitor.config.ts': 'ionic',
313
+ 'capacitor.config.js': 'ionic',
314
+
315
+ // Database
316
+ 'drizzle.config.ts': 'drizzle',
317
+ 'drizzle.config.js': 'drizzle',
318
+ 'prisma/schema.prisma': 'prisma',
319
+ 'sequelize.config.js': 'sequelize',
320
+
321
+ // CMS
322
+ 'sanity.config.ts': 'sanity',
323
+ 'sanity.config.js': 'sanity',
324
+ 'payload.config.ts': 'payload',
325
+ 'payload.config.js': 'payload',
326
+ };
327
+
328
+ for (const [file, framework] of Object.entries(filePatterns)) {
329
+ if (await fs.pathExists(path.join(this.rootDir, file))) {
330
+ this.detectedFramework = { name: framework, ...FRAMEWORKS[framework] };
331
+ this.projectType = FRAMEWORKS[framework].type;
332
+ return;
333
+ }
334
+ }
335
+ }
336
+
337
+ async detectBundler() {
338
+ if (!this.packageJson) return;
339
+
340
+ const deps = {
341
+ ...this.packageJson.dependencies,
342
+ ...this.packageJson.devDependencies,
343
+ };
344
+
345
+ const scripts = this.packageJson.scripts || {};
346
+
347
+ // Check for bundler in dependencies
348
+ for (const bundler of Object.keys(BUNDLERS)) {
349
+ if (deps[bundler] || deps[`@${bundler}/core`]) {
350
+ this.detectedBundler = bundler;
351
+ return;
352
+ }
353
+ }
354
+
355
+ // Check scripts for bundler usage
356
+ const scriptContent = Object.values(scripts).join(' ');
357
+ for (const bundler of Object.keys(BUNDLERS)) {
358
+ if (scriptContent.includes(bundler)) {
359
+ this.detectedBundler = bundler;
360
+ return;
361
+ }
362
+ }
363
+
364
+ // Default bundler based on framework
365
+ if (this.detectedFramework) {
366
+ const defaultBundlers = {
367
+ nextjs: 'turbopack',
368
+ nuxt: 'vite',
369
+ sveltekit: 'vite',
370
+ astro: 'vite',
371
+ solidstart: 'vite',
372
+ react: 'esbuild',
373
+ vue: 'vite',
374
+ angular: 'webpack',
375
+ svelte: 'vite',
376
+ electron: 'webpack',
377
+ };
378
+ this.detectedBundler = defaultBundlers[this.detectedFramework.name] || 'esbuild';
379
+ } else {
380
+ this.detectedBundler = 'esbuild';
381
+ }
382
+ }
383
+
384
+ async detectTypeScript() {
385
+ this.isTypeScript = await fs.pathExists(path.join(this.rootDir, 'tsconfig.json'));
386
+ }
387
+
388
+ async detectMonorepo() {
389
+ this.isMonorepo = await fs.pathExists(path.join(this.rootDir, 'lerna.json')) ||
390
+ await fs.pathExists(path.join(this.rootDir, 'pnpm-workspace.yaml')) ||
391
+ await fs.pathExists(path.join(this.rootDir, 'turbo.json')) ||
392
+ (this.packageJson?.workspaces !== undefined);
393
+ }
394
+
395
+ getConfig() {
396
+ return {
397
+ framework: this.detectedFramework,
398
+ bundler: this.detectedBundler,
399
+ type: this.projectType,
400
+ isTypeScript: this.isTypeScript,
401
+ isMonorepo: this.isMonorepo,
402
+ rootDir: this.rootDir,
403
+ };
404
+ }
405
+ }
406
+
407
+ module.exports = ProjectDetector;
@@ -0,0 +1,106 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const os = require('os');
4
+ const logger = require('./logger');
5
+
6
+ const EASY_HOME = path.join(os.homedir(), '.easy');
7
+ const GLOBAL_CONFIG_PATH = path.join(EASY_HOME, 'config.json');
8
+
9
+ const DEFAULT_GLOBAL_CONFIG = {
10
+ // Shared modules settings
11
+ sharedModules: {
12
+ enabled: true,
13
+ autoSync: true,
14
+ autoInstall: true,
15
+ },
16
+
17
+ // Default build settings
18
+ build: {
19
+ minify: true,
20
+ sourcemap: false,
21
+ outDir: 'dist',
22
+ },
23
+
24
+ // Default dev server settings
25
+ dev: {
26
+ port: 3000,
27
+ host: 'localhost',
28
+ open: true,
29
+ },
30
+
31
+ // Default electron settings
32
+ electron: {
33
+ platforms: ['current'],
34
+ arch: ['x64'],
35
+ },
36
+
37
+ // Telemetry (opt-in)
38
+ telemetry: false,
39
+ };
40
+
41
+ class GlobalConfig {
42
+ constructor() {
43
+ this.config = null;
44
+ }
45
+
46
+ async load() {
47
+ await this.ensureConfigExists();
48
+ this.config = await fs.readJson(GLOBAL_CONFIG_PATH);
49
+ return this.config;
50
+ }
51
+
52
+ async save() {
53
+ await fs.ensureDir(EASY_HOME);
54
+ await fs.writeJson(GLOBAL_CONFIG_PATH, this.config, { spaces: 2 });
55
+ }
56
+
57
+ async ensureConfigExists() {
58
+ await fs.ensureDir(EASY_HOME);
59
+ if (!(await fs.pathExists(GLOBAL_CONFIG_PATH))) {
60
+ await fs.writeJson(GLOBAL_CONFIG_PATH, DEFAULT_GLOBAL_CONFIG, { spaces: 2 });
61
+ }
62
+ }
63
+
64
+ get(key) {
65
+ if (!this.config) return null;
66
+ return key.split('.').reduce((obj, k) => obj?.[k], this.config);
67
+ }
68
+
69
+ set(key, value) {
70
+ if (!this.config) return;
71
+ const keys = key.split('.');
72
+ let obj = this.config;
73
+
74
+ for (let i = 0; i < keys.length - 1; i++) {
75
+ if (!obj[keys[i]]) obj[keys[i]] = {};
76
+ obj = obj[keys[i]];
77
+ }
78
+
79
+ obj[keys[keys.length - 1]] = value;
80
+ }
81
+
82
+ async enableSharedModules() {
83
+ await this.load();
84
+ this.set('sharedModules.enabled', true);
85
+ await this.save();
86
+ logger.success('Shared modules enabled globally');
87
+ }
88
+
89
+ async disableSharedModules() {
90
+ await this.load();
91
+ this.set('sharedModules.enabled', false);
92
+ await this.save();
93
+ logger.success('Shared modules disabled globally');
94
+ }
95
+
96
+ async isSharedModulesEnabled() {
97
+ await this.load();
98
+ return this.get('sharedModules.enabled') || false;
99
+ }
100
+
101
+ getConfigPath() {
102
+ return GLOBAL_CONFIG_PATH;
103
+ }
104
+ }
105
+
106
+ module.exports = new GlobalConfig();
@@ -0,0 +1,98 @@
1
+ const chalk = require('chalk');
2
+ const ora = require('ora');
3
+
4
+ class Logger {
5
+ constructor() {
6
+ this.spinner = null;
7
+ }
8
+
9
+ info(message) {
10
+ console.log(chalk.blue('ℹ'), message);
11
+ }
12
+
13
+ success(message) {
14
+ console.log(chalk.green('✓'), message);
15
+ }
16
+
17
+ warning(message) {
18
+ console.log(chalk.yellow('⚠'), message);
19
+ }
20
+
21
+ error(message) {
22
+ console.log(chalk.red('✖'), message);
23
+ }
24
+
25
+ fun(message) {
26
+ console.log(chalk.magenta('✨'), message);
27
+ }
28
+
29
+ startSpinner(message) {
30
+ this.spinner = ora({
31
+ text: message,
32
+ spinner: 'dots',
33
+ color: 'cyan',
34
+ }).start();
35
+ return this.spinner;
36
+ }
37
+
38
+ stopSpinner(message, success = true) {
39
+ if (this.spinner) {
40
+ if (success) {
41
+ this.spinner.succeed(message);
42
+ } else {
43
+ this.spinner.fail(message);
44
+ }
45
+ this.spinner = null;
46
+ }
47
+ }
48
+
49
+ header(message) {
50
+ console.log('');
51
+ console.log(chalk.bold.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
52
+ console.log(chalk.bold.cyan(` ${message}`));
53
+ console.log(chalk.bold.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
54
+ console.log('');
55
+ }
56
+
57
+ banner() {
58
+ console.log('');
59
+ console.log(chalk.bold.green('🚀 easy-build v1.0.0'));
60
+ console.log(chalk.gray(' The universal build tool for EVERYTHING'));
61
+ console.log('');
62
+ }
63
+
64
+ section(title) {
65
+ console.log('');
66
+ console.log(chalk.bold.white(`📦 ${title}`));
67
+ console.log(chalk.gray('─'.repeat(50)));
68
+ }
69
+
70
+ dim(message) {
71
+ console.log(chalk.gray(message));
72
+ }
73
+
74
+ bold(message) {
75
+ console.log(chalk.bold.white(message));
76
+ }
77
+
78
+ list(items) {
79
+ items.forEach(item => {
80
+ console.log(` ${chalk.cyan('•')} ${item}`);
81
+ });
82
+ }
83
+
84
+ progress(current, total, label = '') {
85
+ const percentage = Math.round((current / total) * 100);
86
+ const filled = Math.round(percentage / 5);
87
+ const empty = 20 - filled;
88
+ const bar = '█'.repeat(filled) + '░'.repeat(empty);
89
+
90
+ console.log(`\r${chalk.cyan(bar)} ${chalk.white(`${percentage}%`)} ${label}`);
91
+ }
92
+
93
+ emoji(text, emoji) {
94
+ console.log(`${emoji} ${text}`);
95
+ }
96
+ }
97
+
98
+ module.exports = new Logger();