create-nexora-next 0.3.7 → 0.4.7

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,119 @@
1
+ const VALID_PMS = ['npm', 'pnpm', 'bun', 'yarn']
2
+
3
+ const FLAGS = {
4
+ '--all': { key: 'all' },
5
+ '--i18n': { key: 'i18n' },
6
+ '--query': { key: 'query' },
7
+ '--theming': { key: 'theming' },
8
+ '--animations': { key: 'animations' },
9
+ '--auth': { key: 'auth' },
10
+ '--axios': { key: 'axios' },
11
+ '--husky': { key: 'husky' },
12
+ '--rc': { key: 'reactCompiler' },
13
+ '--react-compiler': { key: 'reactCompiler' },
14
+ '--no-theming': { key: 'theming', value: false },
15
+ '--no-husky': { key: 'husky', value: false },
16
+ '--no-rc': { key: 'reactCompiler', value: false },
17
+ '--pm': { key: 'pm', takesValue: true },
18
+ '-y': { key: 'yes' },
19
+ '--yes': { key: 'yes' },
20
+ '--help': { key: 'help' },
21
+ '-h': { key: 'help' },
22
+ '--version': { key: 'version' },
23
+ '-v': { key: 'version' },
24
+ }
25
+
26
+ export function parseArgs(argv) {
27
+ const args = argv.slice(2)
28
+ const result = {
29
+ name: null,
30
+ pm: null,
31
+ yes: false,
32
+ help: false,
33
+ version: false,
34
+ all: false,
35
+ i18n: null,
36
+ query: null,
37
+ theming: null,
38
+ animations: null,
39
+ auth: null,
40
+ axios: null,
41
+ husky: null,
42
+ reactCompiler: null,
43
+ }
44
+
45
+ let i = 0
46
+ while (i < args.length) {
47
+ const arg = args[i]
48
+ const def = FLAGS[arg]
49
+
50
+ if (def) {
51
+ if (def.takesValue) {
52
+ result[def.key] = args[++i] ?? null
53
+ } else if (def.value === false) {
54
+ result[def.key] = false
55
+ } else {
56
+ result[def.key] = true
57
+ }
58
+ } else if (!arg.startsWith('-') && !result.name) {
59
+ result.name = arg
60
+ }
61
+ i++
62
+ }
63
+
64
+ if (result.all) {
65
+ for (const key of ['i18n','query','theming','animations','auth','axios','husky','reactCompiler']) {
66
+ if (result[key] === null) result[key] = true
67
+ }
68
+ }
69
+
70
+ if (result.pm && !VALID_PMS.includes(result.pm)) {
71
+ result.pm = null
72
+ }
73
+
74
+ return result
75
+ }
76
+
77
+ export function hasAnyFlag(parsed) {
78
+ return (
79
+ parsed.yes ||
80
+ parsed.all ||
81
+ parsed.name !== null ||
82
+ parsed.pm !== null ||
83
+ ['i18n','query','theming','animations','auth','axios','husky','reactCompiler']
84
+ .some(k => parsed[k] !== null)
85
+ )
86
+ }
87
+
88
+ export function printHelp(version) {
89
+ console.log(`
90
+ create-nexora-next v${version}
91
+
92
+ Usage:
93
+ npx create-nexora-next [name] [flags]
94
+
95
+ Flags:
96
+ --pm <npm|pnpm|bun|yarn> Package manager (default: prompt)
97
+ --all Enable every feature
98
+ --i18n Localization via next-intl
99
+ --query TanStack Query + persistence
100
+ --theming Theming via next-themes
101
+ --animations Motion + GSAP
102
+ --auth Auth proxy + validators
103
+ --axios Axios client/server instances
104
+ --husky Husky pre-commit hooks
105
+ --rc / --react-compiler React Compiler
106
+ --no-theming Skip theming
107
+ --no-husky Skip Husky
108
+ --no-rc Skip React Compiler
109
+ -y / --yes Accept all defaults (no prompts)
110
+ -v / --version Print version
111
+ -h / --help Show this help
112
+
113
+ Examples:
114
+ npx create-nexora-next my-app --pm pnpm --all
115
+ npx create-nexora-next my-app --pm bun --i18n --query --theming
116
+ npx create-nexora-next my-app --pm bun --all --no-animations --no-auth
117
+ npx create-nexora-next my-app -y
118
+ `)
119
+ }
@@ -1,50 +1,50 @@
1
- import { execSync } from 'child_process'
2
-
3
- /**
4
- * Run a shell command with live output, throwing on failure.
5
- * @param {string} cmd
6
- * @param {string} cwd
7
- */
8
- export function run(cmd, cwd) {
9
- execSync(cmd, { cwd, stdio: 'inherit' })
10
- }
11
-
12
- /**
13
- * Run silently, capturing output. Returns stdout string.
14
- * @param {string} cmd
15
- * @param {string} cwd
16
- */
17
- export function runSilent(cmd, cwd) {
18
- return execSync(cmd, { cwd, stdio: 'pipe' }).toString().trim()
19
- }
20
-
21
- /**
22
- * Returns the install command for the given package manager.
23
- * @param {'npm'|'pnpm'|'bun'|'yarn'} pm
24
- * @param {string[]} deps
25
- * @param {boolean} dev
26
- */
27
- export function installCmd(pm, deps, dev = false) {
28
- const flag = dev
29
- ? pm === 'npm' ? '--save-dev' : '-D'
30
- : ''
31
- const pkgs = deps.join(' ')
32
- switch (pm) {
33
- case 'yarn': return `yarn add ${flag} ${pkgs}`.trim()
34
- case 'pnpm': return `pnpm add ${flag} ${pkgs}`.trim()
35
- case 'bun': return `bun add ${flag} ${pkgs}`.trim()
36
- default: return `npm install ${flag} ${pkgs}`.trim()
37
- }
38
- }
39
-
40
- /**
41
- * Returns the exec command (npx / pnpx / bunx).
42
- * @param {'npm'|'pnpm'|'bun'|'yarn'} pm
43
- */
44
- export function execCmd(pm) {
45
- switch (pm) {
46
- case 'pnpm': return 'pnpx'
47
- case 'bun': return 'bunx'
48
- default: return 'npx'
49
- }
1
+ import { execSync } from 'child_process'
2
+
3
+ /**
4
+ * Run a shell command with live output, throwing on failure.
5
+ * @param {string} cmd
6
+ * @param {string} cwd
7
+ */
8
+ export function run(cmd, cwd) {
9
+ execSync(cmd, { cwd, stdio: 'inherit' })
10
+ }
11
+
12
+ /**
13
+ * Run silently, capturing output. Returns stdout string.
14
+ * @param {string} cmd
15
+ * @param {string} cwd
16
+ */
17
+ export function runSilent(cmd, cwd) {
18
+ return execSync(cmd, { cwd, stdio: 'pipe' }).toString().trim()
19
+ }
20
+
21
+ /**
22
+ * Returns the install command for the given package manager.
23
+ * @param {'npm'|'pnpm'|'bun'|'yarn'} pm
24
+ * @param {string[]} deps
25
+ * @param {boolean} dev
26
+ */
27
+ export function installCmd(pm, deps, dev = false) {
28
+ const flag = dev
29
+ ? pm === 'npm' ? '--save-dev' : '-D'
30
+ : ''
31
+ const pkgs = deps.join(' ')
32
+ switch (pm) {
33
+ case 'yarn': return `yarn add ${flag} ${pkgs}`.trim()
34
+ case 'pnpm': return `pnpm add ${flag} ${pkgs}`.trim()
35
+ case 'bun': return `bun add ${flag} ${pkgs}`.trim()
36
+ default: return `npm install ${flag} ${pkgs}`.trim()
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Returns the exec command (npx / pnpx / bunx).
42
+ * @param {'npm'|'pnpm'|'bun'|'yarn'} pm
43
+ */
44
+ export function execCmd(pm) {
45
+ switch (pm) {
46
+ case 'pnpm': return 'pnpx'
47
+ case 'bun': return 'bunx'
48
+ default: return 'npx'
49
+ }
50
50
  }
@@ -1,43 +1,43 @@
1
- import * as p from '@clack/prompts'
2
- import pc from 'picocolors'
3
-
4
- /**
5
- * Wraps a step function with automatic retry-on-failure UX.
6
- * If the step throws, shows the error, prompts "Fix it and press Enter to retry",
7
- * and loops until success or the user cancels.
8
- *
9
- * @param {string} label Human-readable step name (shown in spinner)
10
- * @param {()=>Promise<void>|void} fn The step to execute
11
- */
12
- export async function safeStep(label, fn) {
13
- while (true) {
14
- const spinner = p.spinner()
15
- spinner.start(label)
16
- try {
17
- await fn()
18
- spinner.stop(pc.green(`✓ ${label}`))
19
- return
20
- } catch (err) {
21
- spinner.stop(pc.red(`✗ ${label} failed`))
22
-
23
- const message = err?.message || String(err)
24
- p.log.error(pc.red(message))
25
- p.log.warn(
26
- pc.yellow(
27
- `Fix the issue above, then press ${pc.bold('Enter')} to retry — or Ctrl+C to abort.`,
28
- ),
29
- )
30
-
31
- const retry = await p.confirm({
32
- message: 'Ready to retry?',
33
- initialValue: true,
34
- })
35
-
36
- if (p.isCancel(retry) || !retry) {
37
- p.cancel('Setup aborted.')
38
- process.exit(1)
39
- }
40
- // loop again
41
- }
42
- }
1
+ import * as p from '@clack/prompts'
2
+ import pc from 'picocolors'
3
+
4
+ /**
5
+ * Wraps a step function with automatic retry-on-failure UX.
6
+ * If the step throws, shows the error, prompts "Fix it and press Enter to retry",
7
+ * and loops until success or the user cancels.
8
+ *
9
+ * @param {string} label Human-readable step name (shown in spinner)
10
+ * @param {()=>Promise<void>|void} fn The step to execute
11
+ */
12
+ export async function safeStep(label, fn) {
13
+ while (true) {
14
+ const spinner = p.spinner()
15
+ spinner.start(label)
16
+ try {
17
+ await fn()
18
+ spinner.stop(pc.green(`✓ ${label}`))
19
+ return
20
+ } catch (err) {
21
+ spinner.stop(pc.red(`✗ ${label} failed`))
22
+
23
+ const message = err?.message || String(err)
24
+ p.log.error(pc.red(message))
25
+ p.log.warn(
26
+ pc.yellow(
27
+ `Fix the issue above, then press ${pc.bold('Enter')} to retry — or Ctrl+C to abort.`,
28
+ ),
29
+ )
30
+
31
+ const retry = await p.confirm({
32
+ message: 'Ready to retry?',
33
+ initialValue: true,
34
+ })
35
+
36
+ if (p.isCancel(retry) || !retry) {
37
+ p.cancel('Setup aborted.')
38
+ process.exit(1)
39
+ }
40
+ // loop again
41
+ }
42
+ }
43
43
  }
@@ -1,38 +1,38 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
-
4
- /**
5
- * Write content to a file, creating parent directories as needed.
6
- * @param {string} filePath Absolute path
7
- * @param {string} content
8
- */
9
- export function writeFile(filePath, content) {
10
- fs.mkdirSync(path.dirname(filePath), { recursive: true })
11
- fs.writeFileSync(filePath, content, 'utf8')
12
- }
13
-
14
- /**
15
- * Append content to an existing file.
16
- * @param {string} filePath Absolute path
17
- * @param {string} content
18
- */
19
- export function appendFile(filePath, content) {
20
- fs.appendFileSync(filePath, content, 'utf8')
21
- }
22
-
23
- /**
24
- * Create a directory (and all parents) if it doesn't exist.
25
- * @param {string} dirPath Absolute path
26
- */
27
- export function mkdir(dirPath) {
28
- fs.mkdirSync(dirPath, { recursive: true })
29
- }
30
-
31
- /**
32
- * Check whether a path exists.
33
- * @param {string} p
34
- * @returns {boolean}
35
- */
36
- export function exists(p) {
37
- return fs.existsSync(p)
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+
4
+ /**
5
+ * Write content to a file, creating parent directories as needed.
6
+ * @param {string} filePath Absolute path
7
+ * @param {string} content
8
+ */
9
+ export function writeFile(filePath, content) {
10
+ fs.mkdirSync(path.dirname(filePath), { recursive: true })
11
+ fs.writeFileSync(filePath, content, 'utf8')
12
+ }
13
+
14
+ /**
15
+ * Append content to an existing file.
16
+ * @param {string} filePath Absolute path
17
+ * @param {string} content
18
+ */
19
+ export function appendFile(filePath, content) {
20
+ fs.appendFileSync(filePath, content, 'utf8')
21
+ }
22
+
23
+ /**
24
+ * Create a directory (and all parents) if it doesn't exist.
25
+ * @param {string} dirPath Absolute path
26
+ */
27
+ export function mkdir(dirPath) {
28
+ fs.mkdirSync(dirPath, { recursive: true })
29
+ }
30
+
31
+ /**
32
+ * Check whether a path exists.
33
+ * @param {string} p
34
+ * @returns {boolean}
35
+ */
36
+ export function exists(p) {
37
+ return fs.existsSync(p)
38
38
  }