apexcss-cli 0.1.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,189 @@
1
+ /**
2
+ * Framework detection utility
3
+ * Detects which framework the user's project is using
4
+ */
5
+
6
+ import { readFileSync, existsSync } from 'node:fs';
7
+ import { resolve } from 'node:path';
8
+
9
+ /**
10
+ * Framework definitions with their detection criteria
11
+ */
12
+ export const FRAMEWORKS = {
13
+ next: {
14
+ name: 'Next.js',
15
+ detect: (pkg) => pkg.dependencies?.next || pkg.devDependencies?.next,
16
+ entryFiles: ['src/app/layout.tsx', 'src/app/layout.jsx', 'app/layout.tsx', 'app/layout.jsx'],
17
+ importStatement: 'import \'apexcss\';\n',
18
+ cssConfig: '// Import in layout.tsx:\nimport \'apexcss/base\';\nimport \'apexcss/utilities\';\nimport \'apexcss/themes\';\n',
19
+ configFile: 'next.config.js'
20
+ },
21
+ nuxt: {
22
+ name: 'Nuxt',
23
+ detect: (pkg) => pkg.dependencies?.nuxt || pkg.devDependencies?.nuxt,
24
+ entryFiles: ['nuxt.config.ts', 'nuxt.config.js'],
25
+ cssConfig: 'css: [\'~/apexcss/apex.css\']',
26
+ importStatement: null // Nuxt uses CSS config in nuxt.config
27
+ },
28
+ react: {
29
+ name: 'React',
30
+ detect: (pkg) => pkg.dependencies?.react && !pkg.dependencies?.next,
31
+ entryFiles: ['src/index.css', 'src/main.css', 'src/styles.css'],
32
+ importStatement: '@import \'apexcss\';\n',
33
+ fallbackFile: 'src/index.css'
34
+ },
35
+ vue: {
36
+ name: 'Vue',
37
+ detect: (pkg) => pkg.dependencies?.vue && !pkg.dependencies?.nuxt,
38
+ entryFiles: ['src/style.css', 'src/styles.css', 'src/main.css'],
39
+ importStatement: '@import \'apexcss\';\n',
40
+ fallbackFile: 'src/style.css'
41
+ },
42
+ angular: {
43
+ name: 'Angular',
44
+ detect: (pkg) => pkg.dependencies?.['@angular/core'],
45
+ entryFiles: ['src/styles.css', 'src/styles.scss', 'angular.json'],
46
+ importStatement: '@import \'apexcss\';\n',
47
+ configFile: 'angular.json'
48
+ },
49
+ svelte: {
50
+ name: 'Svelte',
51
+ detect: (pkg) => pkg.dependencies?.svelte || pkg.devDependencies?.svelte,
52
+ entryFiles: ['src/app.css', 'src/style.css', 'src/styles.css'],
53
+ importStatement: '@import \'apexcss\';\n',
54
+ fallbackFile: 'src/app.css'
55
+ },
56
+ astro: {
57
+ name: 'Astro',
58
+ detect: (pkg) => pkg.dependencies?.astro || pkg.devDependencies?.astro,
59
+ entryFiles: ['src/styles/global.css', 'src/style.css', 'src/layouts/Layout.astro'],
60
+ importStatement: '@import \'apexcss\';\n',
61
+ fallbackFile: 'src/styles/global.css'
62
+ },
63
+ vanilla: {
64
+ name: 'Vanilla/Vite',
65
+ detect: () => true, // Fallback
66
+ entryFiles: ['src/style.css', 'src/styles.css', 'style.css', 'styles.css'],
67
+ importStatement: '@import \'apexcss\';\n',
68
+ fallbackFile: 'src/style.css'
69
+ }
70
+ };
71
+
72
+ /**
73
+ * Detect the framework being used in the current project
74
+ * @param {string} cwd - Current working directory
75
+ * @returns {object} - Detected framework info
76
+ */
77
+ export function detectFramework(cwd = process.cwd()) {
78
+ // Read package.json
79
+ const packageJsonPath = resolve(cwd, 'package.json');
80
+
81
+ if (!existsSync(packageJsonPath)) {
82
+ return {
83
+ id: 'vanilla',
84
+ ...FRAMEWORKS.vanilla,
85
+ detected: false,
86
+ hasPackageJson: false
87
+ };
88
+ }
89
+
90
+ let pkg;
91
+ try {
92
+ pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
93
+ } catch {
94
+ return {
95
+ id: 'vanilla',
96
+ ...FRAMEWORKS.vanilla,
97
+ detected: false,
98
+ hasPackageJson: true,
99
+ parseError: true
100
+ };
101
+ }
102
+
103
+ // Check each framework in order (more specific first)
104
+ const frameworkOrder = ['next', 'nuxt', 'angular', 'svelte', 'astro', 'react', 'vue', 'vanilla'];
105
+
106
+ for (const frameworkId of frameworkOrder) {
107
+ const framework = FRAMEWORKS[frameworkId];
108
+ if (framework.detect(pkg)) {
109
+ // Find the actual entry file that exists
110
+ const existingEntry = framework.entryFiles.find(file =>
111
+ existsSync(resolve(cwd, file))
112
+ );
113
+
114
+ return {
115
+ id: frameworkId,
116
+ ...framework,
117
+ detected: frameworkId !== 'vanilla',
118
+ hasPackageJson: true,
119
+ entryFile: existingEntry || framework.fallbackFile,
120
+ packageJson: pkg
121
+ };
122
+ }
123
+ }
124
+
125
+ // Should not reach here due to vanilla fallback
126
+ return {
127
+ id: 'vanilla',
128
+ ...FRAMEWORKS.vanilla,
129
+ detected: false,
130
+ hasPackageJson: true
131
+ };
132
+ }
133
+
134
+ /**
135
+ * Get all available frameworks for selection
136
+ * @returns {Array} - List of framework options
137
+ */
138
+ export function getAvailableFrameworks() {
139
+ return [
140
+ { id: 'next', name: 'Next.js' },
141
+ { id: 'nuxt', name: 'Nuxt' },
142
+ { id: 'react', name: 'React (Vite)' },
143
+ { id: 'vue', name: 'Vue (Vite)' },
144
+ { id: 'angular', name: 'Angular' },
145
+ { id: 'svelte', name: 'Svelte (Vite)' },
146
+ { id: 'astro', name: 'Astro' },
147
+ { id: 'vanilla', name: 'Vanilla/Vite' }
148
+ ];
149
+ }
150
+
151
+ /**
152
+ * Get framework-specific output directory recommendation
153
+ * @param {string} frameworkId - Framework identifier
154
+ * @returns {string} - Recommended output directory
155
+ */
156
+ export function getRecommendedOutputDir(frameworkId) {
157
+ const recommendations = {
158
+ next: './dist/',
159
+ nuxt: './dist/',
160
+ react: './dist/',
161
+ vue: './dist/',
162
+ angular: './dist/',
163
+ svelte: './dist/',
164
+ astro: './dist/',
165
+ vanilla: './dist/'
166
+ };
167
+
168
+ return recommendations[frameworkId] || './dist/';
169
+ }
170
+
171
+ /**
172
+ * Check if a framework uses a specific configuration approach
173
+ * @param {string} frameworkId - Framework identifier
174
+ * @returns {object} - Configuration approach
175
+ */
176
+ export function getFrameworkConfigApproach(frameworkId) {
177
+ const approaches = {
178
+ next: { type: 'import', supportsCSSImport: true },
179
+ nuxt: { type: 'config', configKey: 'css' },
180
+ react: { type: 'import', supportsCSSImport: true },
181
+ vue: { type: 'import', supportsCSSImport: true },
182
+ angular: { type: 'styles', supportsGlobalStyles: true },
183
+ svelte: { type: 'import', supportsCSSImport: true },
184
+ astro: { type: 'import', supportsCSSImport: true },
185
+ vanilla: { type: 'import', supportsCSSImport: true }
186
+ };
187
+
188
+ return approaches[frameworkId] || { type: 'import' };
189
+ }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Logger utility for consistent CLI output
3
+ */
4
+
5
+ // Simple ANSI color codes
6
+ const colors = {
7
+ reset: '\x1b[0m',
8
+ bright: '\x1b[1m',
9
+ dim: '\x1b[2m',
10
+ red: '\x1b[31m',
11
+ green: '\x1b[32m',
12
+ yellow: '\x1b[33m',
13
+ blue: '\x1b[34m',
14
+ magenta: '\x1b[35m',
15
+ cyan: '\x1b[36m'
16
+ };
17
+
18
+ /**
19
+ * Format a message with color
20
+ * @param {string} text
21
+ * @param {string} color
22
+ * @returns {string}
23
+ */
24
+ /**
25
+ * Format a message with color
26
+ * @param {string} text - Text to colorize
27
+ * @param {string} color - Color name
28
+ * @returns {string} - Colorized text
29
+ */
30
+ function colorize(text, color) {
31
+ return `${colors[color]}${text}${colors.reset}`;
32
+ }
33
+
34
+ export const logger = {
35
+ /**
36
+ * Info message
37
+ * @param {string} message
38
+ */
39
+ info(message) {
40
+ console.log(`${colorize('[apexcss]', 'cyan')} ${message}`);
41
+ },
42
+
43
+ /**
44
+ * Success message
45
+ * @param {string} message
46
+ */
47
+ success(message) {
48
+ console.log(`${colorize('[apexcss]', 'green')} ${colorize('✔', 'green')} ${message}`);
49
+ },
50
+
51
+ /**
52
+ * Warning message
53
+ * @param {string} message
54
+ */
55
+ warn(message) {
56
+ console.warn(`${colorize('[apexcss]', 'yellow')} ${colorize('⚠', 'yellow')} ${message}`);
57
+ },
58
+
59
+ /**
60
+ * Error message
61
+ * @param {string} message
62
+ */
63
+ error(message) {
64
+ console.error(`${colorize('[apexcss]', 'red')} ${colorize('✖', 'red')} ${message}`);
65
+ },
66
+
67
+ /**
68
+ * Debug message (only shown with DEBUG env var)
69
+ * @param {string} message
70
+ */
71
+ debug(message) {
72
+ if (process.env.DEBUG) {
73
+ console.log(`${colorize('[apexcss]', 'dim')} ${colorize('[debug]', 'magenta')} ${message}`);
74
+ }
75
+ },
76
+
77
+ /**
78
+ * New line
79
+ */
80
+ newline() {
81
+ console.log();
82
+ },
83
+
84
+ /**
85
+ * Section header
86
+ * @param {string} title
87
+ */
88
+ header(title) {
89
+ this.newline();
90
+ console.log(colorize(title, 'bright'));
91
+ console.log(colorize('═'.repeat(title.length), 'dim'));
92
+ },
93
+
94
+ /**
95
+ * List items
96
+ * @param {string[]} items
97
+ */
98
+ list(items) {
99
+ items.forEach(item => {
100
+ console.log(` ${colorize('•', 'cyan')} ${item}`);
101
+ });
102
+ },
103
+
104
+ /**
105
+ * Format file path
106
+ * @param {string} filepath
107
+ * @returns {string}
108
+ */
109
+ path(filepath) {
110
+ return colorize(filepath, 'cyan');
111
+ },
112
+
113
+ /**
114
+ * Format command
115
+ * @param {string} command
116
+ * @returns {string}
117
+ */
118
+ cmd(command) {
119
+ return colorize(command, 'yellow');
120
+ }
121
+ };
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "apexcss-cli",
3
+ "version": "0.1.0",
4
+ "description": "ApexCSS CLI - Build and customize your CSS framework",
5
+ "type": "module",
6
+ "main": "cli/index.js",
7
+ "types": "./package.json",
8
+ "files": [
9
+ "bin/",
10
+ "cli/",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "publishConfig": {
15
+ "access": "public",
16
+ "registry": "https://registry.npmjs.org/"
17
+ },
18
+ "bin": {
19
+ "apexcss": "bin/apexcss.js"
20
+ },
21
+ "scripts": {
22
+ "test": "node tests/run-tests.js",
23
+ "test:unit": "node --test tests/unit/**/*.test.js",
24
+ "test:watch": "node --test --watch tests/unit/**/*.test.js",
25
+ "test:coverage": "c8 node tests/run-tests.js",
26
+ "test:coverage:text": "c8 --reporter=text --reporter=text-summary node tests/run-tests.js",
27
+ "test:coverage:html": "c8 --reporter=html node tests/run-tests.js",
28
+ "lint": "eslint cli/ bin/ tests/",
29
+ "lint:fix": "eslint cli/ bin/ tests/ --fix",
30
+ "doctor": "node bin/apexcss.js doctor",
31
+ "version": "node bin/apexcss.js --version",
32
+ "prepublishOnly": "echo \"Preparing for publish...\""
33
+ },
34
+ "keywords": [
35
+ "css",
36
+ "framework",
37
+ "cli",
38
+ "apexcss",
39
+ "utility-first",
40
+ "sass",
41
+ "scss",
42
+ "build-tool"
43
+ ],
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/chris-briddock/apex-cli.git"
47
+ },
48
+ "author": "",
49
+ "license": "MIT",
50
+ "devDependencies": {
51
+ "c8": "^10.1.3",
52
+ "eslint": "^9.16.0",
53
+ "eslint-plugin-jsdoc": "^50.6.1",
54
+ "globals": "^15.14.0"
55
+ },
56
+ "dependencies": {
57
+ "chalk": "^5.3.0",
58
+ "commander": "^12.0.0"
59
+ },
60
+ "optionalDependencies": {
61
+ "chokidar": "^3.6.0",
62
+ "inquirer": "^9.2.0"
63
+ },
64
+ "peerDependencies": {
65
+ "apexcss": ">=0.3.0",
66
+ "sass": ">=1.90.0",
67
+ "vite": ">=7.0.0"
68
+ },
69
+ "engines": {
70
+ "node": ">=18.0.0"
71
+ }
72
+ }