vue-art-e4n 0.0.1

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.
package/bin/cli.js ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import chalk from "chalk";
3
+ import { runCLI } from "../core/runCLI.js";
4
+
5
+ /**
6
+ * Gracefully handles Ctrl+C (SIGINT) interruption.
7
+ * Prevents ugly stack traces and exits cleanly.
8
+ */
9
+ process.on("SIGINT", () => {
10
+ console.log(chalk.yellow("\n⛔ Operation canceled by user.\n"));
11
+ process.exit(0);
12
+ });
13
+
14
+ /**
15
+ * Global handler for unhandled promise rejections.
16
+ * Specifically catches Inquirer ExitPromptError.
17
+ */
18
+ process.on("unhandledRejection", (error) => {
19
+ if (error?.name === "ExitPromptError") {
20
+ console.log(chalk.yellow("\n⛔ Operation canceled.\n"));
21
+ process.exit(0);
22
+ }
23
+
24
+ console.error(chalk.red("Unexpected error:"), error);
25
+ process.exit(1);
26
+ });
27
+
28
+ console.log(chalk.cyan("\n✨ Vue Art CLI – Modular Version\n"));
29
+
30
+ await runCLI();
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Available architectures per framework.
3
+ *
4
+ * @type {Record<string, string[]>}
5
+ */
6
+ export const ARCHITECTURES = {
7
+ nuxt: ["default", "feature", "layered", "enterprise"],
8
+ vue: ["simple", "atomic", "feature", "enterprise"],
9
+ vuetify: ["simple", "feature", "enterprise"],
10
+ };
11
+
12
+ /**
13
+ * Determines the recommended architecture based on project context.
14
+ *
15
+ * @param {Object} params
16
+ * @param {string} params.framework
17
+ * @param {"small"|"medium"|"large"} params.scale
18
+ * @param {"short"|"long"} params.lifetime
19
+ * @param {string[]} params.features
20
+ *
21
+ * @returns {string} Recommended architecture
22
+ */
23
+ export function getRecommendedArchitecture({
24
+ framework,
25
+ scale,
26
+ lifetime,
27
+ features,
28
+ }) {
29
+ const archs = ARCHITECTURES[framework];
30
+ if (framework === "nuxt") {
31
+ if (scale === "large") return "enterprise";
32
+ if (scale === "medium" && features.includes("ts")) return "feature";
33
+ return "default";
34
+ }
35
+ if (framework === "vuetify") {
36
+ if (scale === "large") return "enterprise";
37
+ if (features.includes("ts") && features.includes("router"))
38
+ return "feature";
39
+ return "simple";
40
+ }
41
+ if (framework === "vue") {
42
+ if (scale === "large") return "enterprise";
43
+ if (
44
+ features.includes("ts") &&
45
+ features.includes("router") &&
46
+ features.includes("pinia")
47
+ )
48
+ return "feature";
49
+ if (features.includes("ts")) return "atomic";
50
+ return "simple";
51
+ }
52
+
53
+ return archs[0];
54
+ }
@@ -0,0 +1,13 @@
1
+ export const FEATURE_CHOICES = [
2
+ { name: "TypeScript", value: "ts" },
3
+ { name: "Vue Router", value: "router" },
4
+ { name: "ESLint", value: "eslint" },
5
+ { name: "Vitest (Unit Testing)", value: "vitest" },
6
+ { name: "Cypress (E2E Testing)", value: "cypress" },
7
+ { name: "Tailwind CSS", value: "tailwind" },
8
+ { name: "SCSS / Sass", value: "scss" },
9
+ { name: "PWA Support", value: "pwa" },
10
+ { name: "Axios / HTTP Module", value: "axios" },
11
+ { name: "i18n Module", value: "i18n" },
12
+ { name: "Auth Module", value: "auth" },
13
+ ];
@@ -0,0 +1,55 @@
1
+ export const CORE_PACKAGES = {
2
+ vue: ["vue", "vite", "@vitejs/plugin-vue"],
3
+ vuetify: [
4
+ "vue",
5
+ "vite",
6
+ "@vitejs/plugin-vue",
7
+ "vuetify",
8
+ "vite-plugin-vuetify",
9
+ "@mdi/font",
10
+ ],
11
+ nuxt: ["nuxt"],
12
+ };
13
+
14
+ export const PACKAGE_MAP = {
15
+ vue: {
16
+ ts: ["typescript"],
17
+ router: ["vue-router"],
18
+ pinia: ["pinia"],
19
+ vuex: ["vuex"],
20
+ eslint: ["eslint"],
21
+ vitest: ["vitest"],
22
+ cypress: ["cypress"],
23
+ tailwind: ["tailwindcss", "postcss", "autoprefixer"],
24
+ scss: ["sass"],
25
+ pwa: ["vite-plugin-pwa"],
26
+ axios: ["axios"],
27
+ },
28
+
29
+ vuetify: {
30
+ ts: ["typescript"],
31
+ router: ["vue-router"],
32
+ pinia: ["pinia"],
33
+ vuex: ["vuex"],
34
+ eslint: ["eslint"],
35
+
36
+ tailwind: ["tailwindcss", "postcss", "autoprefixer"],
37
+ pwa: ["vite-plugin-pwa"],
38
+ axios: ["axios"],
39
+ },
40
+
41
+ nuxt: {
42
+ ts: ["@nuxt/typescript-build"],
43
+ pinia: ["@pinia/nuxt"],
44
+ vuex: ["vuex"],
45
+ eslint: ["eslint"],
46
+ pwa: ["@nuxt/pwa"],
47
+ i18n: ["@nuxt/i18n"],
48
+ auth: ["@nuxt/auth-next"],
49
+ axios: ["@nuxt/axios"],
50
+ vitest: ["vitest"],
51
+ cypress: ["cypress"],
52
+ tailwind: ["@nuxt/tailwindcss"],
53
+ vuetify: ["vuetify"],
54
+ },
55
+ };
@@ -0,0 +1,16 @@
1
+ export const EXCLUSIVE_RULES = [
2
+ {
3
+ ifSelected: "eslint",
4
+ disable: "cypress",
5
+ reason: "ESLint selected, Cypress optional",
6
+ },
7
+ {
8
+ ifSelected: "vitest",
9
+ disable: "cypress",
10
+ reason: "Vitest selected, Cypress optional",
11
+ },
12
+ ];
13
+
14
+ export const STORE_ARCHITECTURE_RULES = [
15
+ { store: "vuex", forbiddenArchitectures: ["atomic"] },
16
+ ];
@@ -0,0 +1,131 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ /**
5
+ * Generates a complete package.json in the specified project directory.
6
+ * Includes base dependencies/devDependencies for the selected framework
7
+ * and additional user-specified packages and features.
8
+ *
9
+ * @param {Object} options
10
+ * @param {string} options.projectDir - Path to the project folder.
11
+ * @param {string} [options.projectName] - Name of the project (defaults to folder name).
12
+ * @param {"vue"|"vuetify"|"nuxt"} options.framework - Framework to setup.
13
+ * @param {string[]} [options.features] - Optional features to include (e.g., "vitest").
14
+ * @param {string[]} [options.packages] - Additional packages to include.
15
+ */
16
+
17
+ export function createPackageJson({
18
+ projectDir,
19
+ projectName,
20
+ framework,
21
+ features,
22
+ packages,
23
+ }) {
24
+ const name = (projectName || path.basename(projectDir))
25
+ .replace(/\s+/g, "-")
26
+ .toLowerCase();
27
+
28
+ /** @type {Record<string, any>} */
29
+ const pkg = {
30
+ name,
31
+ version: "1.0.0",
32
+ private: true,
33
+ scripts: {},
34
+ dependencies: {},
35
+ devDependencies: {},
36
+ };
37
+ const baseDependencies = {};
38
+ const baseDevDependencies = {};
39
+
40
+ if (framework === "vue" || framework === "vuetify") {
41
+ pkg.type = "module";
42
+ pkg.scripts = {
43
+ dev: "vite",
44
+ build: "vite build",
45
+ preview: "vite preview",
46
+ };
47
+ baseDependencies["vue"] = "^3.4.0";
48
+ baseDevDependencies["vite"] = "^5.0.0";
49
+ baseDevDependencies["@vitejs/plugin-vue"] = "^5.0.0";
50
+ if (framework === "vuetify") {
51
+ baseDependencies["vuetify"] = "^3.5.0";
52
+ baseDependencies["@mdi/font"] = "^7.4.0";
53
+ }
54
+ }
55
+
56
+ if (framework === "nuxt") {
57
+ pkg.scripts = {
58
+ dev: "nuxt dev",
59
+ build: "nuxt build",
60
+ preview: "nuxt preview",
61
+ generate: "nuxt generate",
62
+ };
63
+ baseDependencies["nuxt"] = "^3.12.0";
64
+ }
65
+ if (features?.includes("vitest")) {
66
+ pkg.scripts.test = "vitest";
67
+ }
68
+ const runtimeDeps = new Set([
69
+ "vue-router",
70
+ "pinia",
71
+ "vuex",
72
+ "axios",
73
+ "vuetify",
74
+ "@mdi/font",
75
+ "@nuxt/pwa",
76
+ "@nuxt/axios",
77
+ "@nuxt/i18n",
78
+ "@nuxt/auth-next",
79
+ "@pinia/nuxt",
80
+ ]);
81
+
82
+ const devDeps = new Set([
83
+ "typescript",
84
+ "vite",
85
+ "@vitejs/plugin-vue",
86
+ "tailwindcss",
87
+ "postcss",
88
+ "autoprefixer",
89
+ "sass",
90
+ "vite-plugin-pwa",
91
+ "eslint",
92
+ "vitest",
93
+ "cypress",
94
+ "@nuxt/typescript-build",
95
+ "@nuxt/tailwindcss",
96
+ ]);
97
+
98
+ Object.entries(baseDependencies).forEach(([pkgName, version]) => {
99
+ pkg.dependencies[pkgName] = version;
100
+ });
101
+
102
+ Object.entries(baseDevDependencies).forEach(([pkgName, version]) => {
103
+ pkg.devDependencies[pkgName] = version;
104
+ });
105
+
106
+ (packages || []).forEach((pkgName) => {
107
+ if (baseDependencies[pkgName] || baseDevDependencies[pkgName]) {
108
+ return;
109
+ }
110
+ if (runtimeDeps.has(pkgName)) {
111
+ if (!pkg.dependencies[pkgName]) {
112
+ pkg.dependencies[pkgName] = "latest";
113
+ }
114
+ } else if (devDeps.has(pkgName)) {
115
+ if (!pkg.devDependencies[pkgName]) {
116
+ pkg.devDependencies[pkgName] = "latest";
117
+ }
118
+ } else {
119
+ if (!pkg.dependencies[pkgName] && !pkg.devDependencies[pkgName]) {
120
+ pkg.dependencies[pkgName] = "latest";
121
+ }
122
+ }
123
+ });
124
+ Object.keys(pkg.scripts).forEach((k) => {
125
+ if (!pkg.scripts[k]) delete pkg.scripts[k];
126
+ });
127
+ if (Object.keys(pkg.dependencies).length === 0) delete pkg.dependencies;
128
+ if (Object.keys(pkg.devDependencies).length === 0) delete pkg.devDependencies;
129
+ const pkgPath = path.join(projectDir, "package.json");
130
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2), "utf-8");
131
+ }