@object-ui/cli 0.3.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.
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/dist/chunk-WOV6EOMH.js +1272 -0
- package/dist/chunk-WOV6EOMH.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +708 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createTempApp,
|
|
4
|
+
createTempAppWithRouting,
|
|
5
|
+
init,
|
|
6
|
+
parseSchemaFile,
|
|
7
|
+
scanPagesDirectory,
|
|
8
|
+
serve
|
|
9
|
+
} from "./chunk-WOV6EOMH.js";
|
|
10
|
+
|
|
11
|
+
// src/cli.ts
|
|
12
|
+
import { Command } from "commander";
|
|
13
|
+
import chalk11 from "chalk";
|
|
14
|
+
|
|
15
|
+
// src/commands/dev.ts
|
|
16
|
+
import { createServer } from "vite";
|
|
17
|
+
import react from "@vitejs/plugin-react";
|
|
18
|
+
import { existsSync, mkdirSync, unlinkSync, statSync } from "fs";
|
|
19
|
+
import { join, resolve, dirname } from "path";
|
|
20
|
+
import chalk from "chalk";
|
|
21
|
+
import { execSync } from "child_process";
|
|
22
|
+
import { createRequire } from "module";
|
|
23
|
+
async function dev(schemaPath, options) {
|
|
24
|
+
const cwd = process.cwd();
|
|
25
|
+
let _projectRoot = cwd;
|
|
26
|
+
const targetSchemaPath = schemaPath;
|
|
27
|
+
let hasPagesDir = false;
|
|
28
|
+
let pagesDir = "";
|
|
29
|
+
let appConfig = null;
|
|
30
|
+
const absoluteSchemaPath = resolve(cwd, schemaPath);
|
|
31
|
+
if (existsSync(absoluteSchemaPath) && statSync(absoluteSchemaPath).isFile()) {
|
|
32
|
+
const fileDir = dirname(absoluteSchemaPath);
|
|
33
|
+
const potentialPagesDir = join(fileDir, "pages");
|
|
34
|
+
if (existsSync(potentialPagesDir)) {
|
|
35
|
+
console.log(chalk.blue(`\u{1F4C2} Detected project structure at ${fileDir}`));
|
|
36
|
+
_projectRoot = fileDir;
|
|
37
|
+
hasPagesDir = true;
|
|
38
|
+
pagesDir = potentialPagesDir;
|
|
39
|
+
try {
|
|
40
|
+
appConfig = parseSchemaFile(absoluteSchemaPath);
|
|
41
|
+
console.log(chalk.blue("\u2699\uFE0F Loaded App Config from app.json"));
|
|
42
|
+
} catch (_e) {
|
|
43
|
+
console.warn("Failed to parse app config");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (!hasPagesDir) {
|
|
48
|
+
const localPagesDir = join(cwd, "pages");
|
|
49
|
+
if (existsSync(localPagesDir)) {
|
|
50
|
+
hasPagesDir = true;
|
|
51
|
+
pagesDir = localPagesDir;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const require2 = createRequire(join(cwd, "package.json"));
|
|
55
|
+
let routes = [];
|
|
56
|
+
let schema = null;
|
|
57
|
+
let useFileSystemRouting = false;
|
|
58
|
+
if (hasPagesDir) {
|
|
59
|
+
console.log(chalk.blue(`\u{1F4C1} Using file-system routing from ${pagesDir}`));
|
|
60
|
+
routes = scanPagesDirectory(pagesDir);
|
|
61
|
+
useFileSystemRouting = true;
|
|
62
|
+
if (routes.length === 0) {
|
|
63
|
+
throw new Error(`No schema files found in ${pagesDir}`);
|
|
64
|
+
}
|
|
65
|
+
console.log(chalk.green(`\u2713 Found ${routes.length} route(s)`));
|
|
66
|
+
routes.forEach((route) => {
|
|
67
|
+
console.log(chalk.dim(` ${route.path} \u2192 ${route.filePath.replace(cwd, ".")}`));
|
|
68
|
+
});
|
|
69
|
+
} else {
|
|
70
|
+
const fullSchemaPath = resolve(cwd, schemaPath);
|
|
71
|
+
if (!existsSync(fullSchemaPath)) {
|
|
72
|
+
throw new Error(`Schema file not found: ${schemaPath}
|
|
73
|
+
Run 'objectui init' to create a sample schema.`);
|
|
74
|
+
}
|
|
75
|
+
console.log(chalk.blue("\u{1F4CB} Loading schema:"), chalk.cyan(schemaPath));
|
|
76
|
+
try {
|
|
77
|
+
schema = parseSchemaFile(fullSchemaPath);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
throw new Error(`Invalid schema file: ${error instanceof Error ? error.message : error}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const tmpDir = join(cwd, ".objectui-tmp");
|
|
83
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
84
|
+
if (useFileSystemRouting) {
|
|
85
|
+
createTempAppWithRouting(tmpDir, routes, appConfig);
|
|
86
|
+
} else {
|
|
87
|
+
createTempApp(tmpDir, schema);
|
|
88
|
+
}
|
|
89
|
+
const isMonorepo = existsSync(join(cwd, "pnpm-workspace.yaml"));
|
|
90
|
+
if (isMonorepo) {
|
|
91
|
+
console.log(chalk.blue("\u{1F4E6} Detected monorepo - using root node_modules"));
|
|
92
|
+
} else {
|
|
93
|
+
console.log(chalk.blue("\u{1F4E6} Installing dependencies..."));
|
|
94
|
+
console.log(chalk.dim(" This may take a moment on first run..."));
|
|
95
|
+
try {
|
|
96
|
+
execSync("npm install --silent --prefer-offline", {
|
|
97
|
+
cwd: tmpDir,
|
|
98
|
+
stdio: "inherit"
|
|
99
|
+
});
|
|
100
|
+
console.log(chalk.green("\u2713 Dependencies installed"));
|
|
101
|
+
} catch {
|
|
102
|
+
throw new Error("Failed to install dependencies. Please check your internet connection and try again.");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
console.log(chalk.green("\u2713 Schema loaded successfully"));
|
|
106
|
+
console.log(chalk.blue("\u{1F680} Starting development server...\n"));
|
|
107
|
+
const viteConfig = {
|
|
108
|
+
root: tmpDir,
|
|
109
|
+
server: {
|
|
110
|
+
port: parseInt(options.port),
|
|
111
|
+
host: options.host,
|
|
112
|
+
open: options.open !== false,
|
|
113
|
+
fs: {
|
|
114
|
+
// Allow serving files from workspace root
|
|
115
|
+
allow: [cwd]
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
resolve: {
|
|
119
|
+
alias: {}
|
|
120
|
+
},
|
|
121
|
+
plugins: [react()]
|
|
122
|
+
};
|
|
123
|
+
if (isMonorepo) {
|
|
124
|
+
console.log(chalk.blue("\u{1F4E6} Detected monorepo - configuring workspace aliases"));
|
|
125
|
+
const postcssPath = join(tmpDir, "postcss.config.js");
|
|
126
|
+
if (existsSync(postcssPath)) {
|
|
127
|
+
unlinkSync(postcssPath);
|
|
128
|
+
}
|
|
129
|
+
viteConfig.resolve.alias = {
|
|
130
|
+
"@object-ui/react": join(cwd, "packages/react/src/index.ts"),
|
|
131
|
+
"@object-ui/components": join(cwd, "packages/components/src/index.ts"),
|
|
132
|
+
"@object-ui/core": join(cwd, "packages/core/src/index.ts"),
|
|
133
|
+
"@object-ui/types": join(cwd, "packages/types/src/index.ts")
|
|
134
|
+
};
|
|
135
|
+
try {
|
|
136
|
+
const lucidePath = require2.resolve("lucide-react", { paths: [join(cwd, "packages/components")] });
|
|
137
|
+
viteConfig.resolve.alias["lucide-react"] = lucidePath;
|
|
138
|
+
} catch (e) {
|
|
139
|
+
console.warn("\u26A0\uFE0F Could not resolve lucide-react automatically:", e);
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
const tailwindcss = require2("tailwindcss");
|
|
143
|
+
const autoprefixer = require2("autoprefixer");
|
|
144
|
+
viteConfig.css = {
|
|
145
|
+
postcss: {
|
|
146
|
+
plugins: [
|
|
147
|
+
tailwindcss(join(tmpDir, "tailwind.config.js")),
|
|
148
|
+
autoprefixer()
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
} catch (_e) {
|
|
153
|
+
console.warn(chalk.yellow("\u26A0\uFE0F Failed to load PostCSS plugins from root node_modules. Styles might not work correctly."));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const server = await createServer(viteConfig);
|
|
157
|
+
await server.listen();
|
|
158
|
+
const { port, host } = server.config.server;
|
|
159
|
+
const protocol = server.config.server.https ? "https" : "http";
|
|
160
|
+
const displayHost = host === "0.0.0.0" ? "localhost" : host;
|
|
161
|
+
console.log();
|
|
162
|
+
console.log(chalk.green("\u2713 Development server started successfully!"));
|
|
163
|
+
console.log();
|
|
164
|
+
console.log(chalk.bold(" Local: ") + chalk.cyan(`${protocol}://${displayHost}:${port}`));
|
|
165
|
+
console.log();
|
|
166
|
+
console.log(chalk.dim(" Press Ctrl+C to stop the server"));
|
|
167
|
+
console.log();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// src/commands/build.ts
|
|
171
|
+
import { build as viteBuild } from "vite";
|
|
172
|
+
import react2 from "@vitejs/plugin-react";
|
|
173
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, cpSync, rmSync } from "fs";
|
|
174
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
175
|
+
import chalk2 from "chalk";
|
|
176
|
+
import { execSync as execSync2 } from "child_process";
|
|
177
|
+
async function buildApp(schemaPath, options) {
|
|
178
|
+
const cwd = process.cwd();
|
|
179
|
+
const outDir = options.outDir || "dist";
|
|
180
|
+
const outputPath = resolve2(cwd, outDir);
|
|
181
|
+
console.log(chalk2.blue("\u{1F528} Building application for production..."));
|
|
182
|
+
console.log();
|
|
183
|
+
const pagesDir = join2(cwd, "pages");
|
|
184
|
+
const hasPagesDir = existsSync2(pagesDir);
|
|
185
|
+
let routes = [];
|
|
186
|
+
let schema = null;
|
|
187
|
+
let useFileSystemRouting = false;
|
|
188
|
+
if (hasPagesDir) {
|
|
189
|
+
console.log(chalk2.blue("\u{1F4C1} Using file-system routing"));
|
|
190
|
+
routes = scanPagesDirectory(pagesDir);
|
|
191
|
+
useFileSystemRouting = true;
|
|
192
|
+
if (routes.length === 0) {
|
|
193
|
+
throw new Error("No schema files found in pages/ directory");
|
|
194
|
+
}
|
|
195
|
+
console.log(chalk2.green(`\u2713 Found ${routes.length} route(s)`));
|
|
196
|
+
} else {
|
|
197
|
+
const fullSchemaPath = resolve2(cwd, schemaPath);
|
|
198
|
+
if (!existsSync2(fullSchemaPath)) {
|
|
199
|
+
throw new Error(`Schema file not found: ${schemaPath}
|
|
200
|
+
Run 'objectui init' to create a sample schema.`);
|
|
201
|
+
}
|
|
202
|
+
console.log(chalk2.blue("\u{1F4CB} Loading schema:"), chalk2.cyan(schemaPath));
|
|
203
|
+
try {
|
|
204
|
+
schema = parseSchemaFile(fullSchemaPath);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
throw new Error(`Invalid schema file: ${error instanceof Error ? error.message : error}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const tmpDir = join2(cwd, ".objectui-tmp");
|
|
210
|
+
mkdirSync2(tmpDir, { recursive: true });
|
|
211
|
+
if (useFileSystemRouting) {
|
|
212
|
+
createTempAppWithRouting(tmpDir, routes);
|
|
213
|
+
} else {
|
|
214
|
+
createTempApp(tmpDir, schema);
|
|
215
|
+
}
|
|
216
|
+
console.log(chalk2.blue("\u{1F4E6} Installing dependencies..."));
|
|
217
|
+
try {
|
|
218
|
+
execSync2("npm install --silent --prefer-offline", {
|
|
219
|
+
cwd: tmpDir,
|
|
220
|
+
stdio: "pipe"
|
|
221
|
+
});
|
|
222
|
+
console.log(chalk2.green("\u2713 Dependencies installed"));
|
|
223
|
+
} catch {
|
|
224
|
+
throw new Error("Failed to install dependencies. Please check your internet connection and try again.");
|
|
225
|
+
}
|
|
226
|
+
console.log(chalk2.blue("\u2699\uFE0F Building with Vite..."));
|
|
227
|
+
console.log();
|
|
228
|
+
if (options.clean && existsSync2(outputPath)) {
|
|
229
|
+
console.log(chalk2.dim(` Cleaning ${outDir}/ directory...`));
|
|
230
|
+
rmSync(outputPath, { recursive: true, force: true });
|
|
231
|
+
}
|
|
232
|
+
try {
|
|
233
|
+
await viteBuild({
|
|
234
|
+
root: tmpDir,
|
|
235
|
+
build: {
|
|
236
|
+
outDir: join2(tmpDir, "dist"),
|
|
237
|
+
emptyOutDir: true,
|
|
238
|
+
reportCompressedSize: true
|
|
239
|
+
},
|
|
240
|
+
plugins: [react2()],
|
|
241
|
+
logLevel: "info"
|
|
242
|
+
});
|
|
243
|
+
mkdirSync2(outputPath, { recursive: true });
|
|
244
|
+
cpSync(join2(tmpDir, "dist"), outputPath, { recursive: true });
|
|
245
|
+
console.log();
|
|
246
|
+
console.log(chalk2.green("\u2713 Build completed successfully!"));
|
|
247
|
+
console.log();
|
|
248
|
+
console.log(chalk2.bold(" Output: ") + chalk2.cyan(outDir + "/"));
|
|
249
|
+
console.log();
|
|
250
|
+
console.log(chalk2.dim(" To serve the production build, run:"));
|
|
251
|
+
console.log(chalk2.cyan(` objectui start --dir ${outDir}`));
|
|
252
|
+
console.log();
|
|
253
|
+
} catch (error) {
|
|
254
|
+
throw new Error(`Build failed: ${error instanceof Error ? error.message : error}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/commands/start.ts
|
|
259
|
+
import express from "express";
|
|
260
|
+
import rateLimit from "express-rate-limit";
|
|
261
|
+
import { existsSync as existsSync3 } from "fs";
|
|
262
|
+
import { join as join3, resolve as resolve3 } from "path";
|
|
263
|
+
import chalk3 from "chalk";
|
|
264
|
+
async function start(options) {
|
|
265
|
+
const cwd = process.cwd();
|
|
266
|
+
const distDir = options.dir || "dist";
|
|
267
|
+
const distPath = resolve3(cwd, distDir);
|
|
268
|
+
if (!existsSync3(distPath)) {
|
|
269
|
+
throw new Error(
|
|
270
|
+
`Build directory not found: ${distDir}
|
|
271
|
+
Run 'objectui build' first to create a production build.`
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
const indexPath = join3(distPath, "index.html");
|
|
275
|
+
if (!existsSync3(indexPath)) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
`index.html not found in ${distDir}/
|
|
278
|
+
Make sure you have a valid production build.`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
console.log(chalk3.blue("\u{1F680} Starting production server...\n"));
|
|
282
|
+
const app = express();
|
|
283
|
+
const port = parseInt(options.port);
|
|
284
|
+
const host = options.host;
|
|
285
|
+
const limiter = rateLimit({
|
|
286
|
+
windowMs: 15 * 60 * 1e3,
|
|
287
|
+
// 15 minutes
|
|
288
|
+
max: 1e3,
|
|
289
|
+
// Limit each IP to 1000 requests per windowMs
|
|
290
|
+
message: "Too many requests from this IP, please try again later.",
|
|
291
|
+
standardHeaders: true,
|
|
292
|
+
// Return rate limit info in the `RateLimit-*` headers
|
|
293
|
+
legacyHeaders: false
|
|
294
|
+
// Disable the `X-RateLimit-*` headers
|
|
295
|
+
});
|
|
296
|
+
app.use(limiter);
|
|
297
|
+
app.use(express.static(distPath));
|
|
298
|
+
app.get("*", (req, res) => {
|
|
299
|
+
res.sendFile(indexPath);
|
|
300
|
+
});
|
|
301
|
+
app.listen(port, host, () => {
|
|
302
|
+
const protocol = "http";
|
|
303
|
+
const displayHost = host === "0.0.0.0" ? "localhost" : host;
|
|
304
|
+
console.log(chalk3.green("\u2713 Production server started successfully!"));
|
|
305
|
+
console.log();
|
|
306
|
+
console.log(chalk3.bold(" Local: ") + chalk3.cyan(`${protocol}://${displayHost}:${port}`));
|
|
307
|
+
console.log(chalk3.bold(" Serving: ") + chalk3.dim(distDir + "/"));
|
|
308
|
+
console.log();
|
|
309
|
+
console.log(chalk3.dim(" Press Ctrl+C to stop the server"));
|
|
310
|
+
console.log();
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/commands/lint.ts
|
|
315
|
+
import { execSync as execSync3 } from "child_process";
|
|
316
|
+
import { existsSync as existsSync4 } from "fs";
|
|
317
|
+
import { join as join4 } from "path";
|
|
318
|
+
import chalk4 from "chalk";
|
|
319
|
+
async function lint(options) {
|
|
320
|
+
const cwd = process.cwd();
|
|
321
|
+
console.log(chalk4.blue("\u{1F50D} Running linter...\n"));
|
|
322
|
+
const tmpDir = join4(cwd, ".objectui-tmp");
|
|
323
|
+
const hasTempApp = existsSync4(tmpDir);
|
|
324
|
+
if (!hasTempApp) {
|
|
325
|
+
throw new Error(
|
|
326
|
+
"No Object UI application found. Run 'objectui dev' first to generate the application."
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
const packageJsonPath = join4(tmpDir, "package.json");
|
|
330
|
+
const nodeModulesPath = join4(tmpDir, "node_modules");
|
|
331
|
+
if (!existsSync4(packageJsonPath) || !existsSync4(nodeModulesPath)) {
|
|
332
|
+
throw new Error(
|
|
333
|
+
"Dependencies not installed. Run 'objectui dev' first to set up the application."
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
try {
|
|
337
|
+
const fixFlag = options.fix ? "--fix" : "";
|
|
338
|
+
const command = `npx eslint "src/**/*.{js,jsx,ts,tsx}" ${fixFlag}`.trim();
|
|
339
|
+
console.log(chalk4.dim(` Running: ${command}
|
|
340
|
+
`));
|
|
341
|
+
execSync3(command, {
|
|
342
|
+
cwd: tmpDir,
|
|
343
|
+
stdio: "inherit"
|
|
344
|
+
});
|
|
345
|
+
console.log();
|
|
346
|
+
console.log(chalk4.green("\u2713 Linting completed successfully!"));
|
|
347
|
+
console.log();
|
|
348
|
+
} catch {
|
|
349
|
+
console.log();
|
|
350
|
+
console.log(chalk4.yellow("\u26A0 Linting found issues."));
|
|
351
|
+
if (!options.fix) {
|
|
352
|
+
console.log(chalk4.dim(" Run 'objectui lint --fix' to automatically fix some issues."));
|
|
353
|
+
}
|
|
354
|
+
console.log();
|
|
355
|
+
process.exit(1);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/commands/test.ts
|
|
360
|
+
import { execSync as execSync4 } from "child_process";
|
|
361
|
+
import { existsSync as existsSync5 } from "fs";
|
|
362
|
+
import { join as join5 } from "path";
|
|
363
|
+
import chalk5 from "chalk";
|
|
364
|
+
async function test(options) {
|
|
365
|
+
const cwd = process.cwd();
|
|
366
|
+
console.log(chalk5.blue("\u{1F9EA} Running tests...\n"));
|
|
367
|
+
const tmpDir = join5(cwd, ".objectui-tmp");
|
|
368
|
+
const hasTempApp = existsSync5(tmpDir);
|
|
369
|
+
if (!hasTempApp) {
|
|
370
|
+
throw new Error(
|
|
371
|
+
"No Object UI application found. Run 'objectui dev' first to generate the application."
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
const packageJsonPath = join5(tmpDir, "package.json");
|
|
375
|
+
const nodeModulesPath = join5(tmpDir, "node_modules");
|
|
376
|
+
if (!existsSync5(packageJsonPath) || !existsSync5(nodeModulesPath)) {
|
|
377
|
+
throw new Error(
|
|
378
|
+
"Dependencies not installed. Run 'objectui dev' first to set up the application."
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
try {
|
|
382
|
+
let command = "npx vitest";
|
|
383
|
+
if (options.watch) {
|
|
384
|
+
command += " --watch";
|
|
385
|
+
} else if (options.ui) {
|
|
386
|
+
command += " --ui";
|
|
387
|
+
} else {
|
|
388
|
+
command += " run";
|
|
389
|
+
}
|
|
390
|
+
if (options.coverage) {
|
|
391
|
+
command += " --coverage";
|
|
392
|
+
}
|
|
393
|
+
console.log(chalk5.dim(` Running: ${command}
|
|
394
|
+
`));
|
|
395
|
+
execSync4(command, {
|
|
396
|
+
cwd: tmpDir,
|
|
397
|
+
stdio: "inherit"
|
|
398
|
+
});
|
|
399
|
+
if (!options.watch && !options.ui) {
|
|
400
|
+
console.log();
|
|
401
|
+
console.log(chalk5.green("\u2713 Tests completed successfully!"));
|
|
402
|
+
console.log();
|
|
403
|
+
}
|
|
404
|
+
} catch {
|
|
405
|
+
console.log();
|
|
406
|
+
console.log(chalk5.red("\u2717 Some tests failed."));
|
|
407
|
+
console.log();
|
|
408
|
+
process.exit(1);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// src/commands/generate.ts
|
|
413
|
+
import chalk6 from "chalk";
|
|
414
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, writeFileSync } from "fs";
|
|
415
|
+
import { join as join6 } from "path";
|
|
416
|
+
async function generate(type, name) {
|
|
417
|
+
const cwd = process.cwd();
|
|
418
|
+
switch (type) {
|
|
419
|
+
case "resource":
|
|
420
|
+
case "object":
|
|
421
|
+
generateResource(cwd, name);
|
|
422
|
+
break;
|
|
423
|
+
case "page":
|
|
424
|
+
generatePage(cwd, name);
|
|
425
|
+
break;
|
|
426
|
+
case "plugin":
|
|
427
|
+
generatePlugin(cwd, name);
|
|
428
|
+
break;
|
|
429
|
+
default:
|
|
430
|
+
console.log(chalk6.red(`Unknown type: ${type}`));
|
|
431
|
+
console.log(`Available types: resource, page, plugin`);
|
|
432
|
+
process.exit(1);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function generateResource(cwd, name) {
|
|
436
|
+
const dir = join6(cwd, "objects");
|
|
437
|
+
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
438
|
+
const fileName = `${name.toLowerCase()}.json`;
|
|
439
|
+
const filePath = join6(dir, fileName);
|
|
440
|
+
if (existsSync6(filePath)) {
|
|
441
|
+
console.log(chalk6.yellow(`Object ${name} already exists at ${filePath}`));
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const content = {
|
|
445
|
+
name,
|
|
446
|
+
fields: {
|
|
447
|
+
name: { type: "text", label: "Name", required: true }
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
writeFileSync(filePath, JSON.stringify(content, null, 2));
|
|
451
|
+
console.log(chalk6.green(`\u2713 Generated resource schema: ${filePath}`));
|
|
452
|
+
}
|
|
453
|
+
function generatePage(cwd, name) {
|
|
454
|
+
const dir = join6(cwd, "pages");
|
|
455
|
+
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
456
|
+
const fileName = `${name.toLowerCase()}.json`;
|
|
457
|
+
const filePath = join6(dir, fileName);
|
|
458
|
+
if (existsSync6(filePath)) {
|
|
459
|
+
console.log(chalk6.yellow(`Page ${name} already exists at ${filePath}`));
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const content = {
|
|
463
|
+
type: "page",
|
|
464
|
+
title: name,
|
|
465
|
+
body: [
|
|
466
|
+
{
|
|
467
|
+
type: "markdown",
|
|
468
|
+
content: `# Welcome to ${name}`
|
|
469
|
+
}
|
|
470
|
+
]
|
|
471
|
+
};
|
|
472
|
+
writeFileSync(filePath, JSON.stringify(content, null, 2));
|
|
473
|
+
console.log(chalk6.green(`\u2713 Generated page schema: ${filePath}`));
|
|
474
|
+
}
|
|
475
|
+
function generatePlugin(cwd, name) {
|
|
476
|
+
const dir = join6(cwd, "plugins", name);
|
|
477
|
+
if (existsSync6(dir)) {
|
|
478
|
+
console.log(chalk6.yellow(`Plugin ${name} already exists`));
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
mkdirSync3(dir, { recursive: true });
|
|
482
|
+
const content = `
|
|
483
|
+
export const ${name}Plugin = {
|
|
484
|
+
name: '${name}',
|
|
485
|
+
install(app) {
|
|
486
|
+
console.log('${name} plugin installed');
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
`;
|
|
490
|
+
writeFileSync(join6(dir, "index.ts"), content.trim());
|
|
491
|
+
console.log(chalk6.green(`\u2713 Generated plugin: ${dir}`));
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// src/commands/doctor.ts
|
|
495
|
+
import chalk7 from "chalk";
|
|
496
|
+
import { existsSync as existsSync7, readFileSync } from "fs";
|
|
497
|
+
import { join as join7 } from "path";
|
|
498
|
+
async function doctor() {
|
|
499
|
+
console.log(chalk7.bold("Object UI Doctor"));
|
|
500
|
+
console.log("Diagnosis in progress...\n");
|
|
501
|
+
const cwd = process.cwd();
|
|
502
|
+
let issues = 0;
|
|
503
|
+
const pkgPath = join7(cwd, "package.json");
|
|
504
|
+
if (existsSync7(pkgPath)) {
|
|
505
|
+
try {
|
|
506
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
507
|
+
const reactVer = pkg.dependencies?.react || pkg.devDependencies?.react;
|
|
508
|
+
if (reactVer) {
|
|
509
|
+
console.log(chalk7.green("\u2713 React installed"));
|
|
510
|
+
} else {
|
|
511
|
+
console.log(chalk7.yellow("\u26A0\uFE0F React not found in dependencies"));
|
|
512
|
+
issues++;
|
|
513
|
+
}
|
|
514
|
+
const tailwindVer = pkg.dependencies?.tailwindcss || pkg.devDependencies?.tailwindcss;
|
|
515
|
+
if (tailwindVer) {
|
|
516
|
+
console.log(chalk7.green("\u2713 Tailwind CSS installed"));
|
|
517
|
+
} else {
|
|
518
|
+
console.log(chalk7.yellow("\u26A0\uFE0F Tailwind CSS not found"));
|
|
519
|
+
issues++;
|
|
520
|
+
}
|
|
521
|
+
} catch (e) {
|
|
522
|
+
console.log(chalk7.red("x Failed to read package.json"));
|
|
523
|
+
issues++;
|
|
524
|
+
}
|
|
525
|
+
} else {
|
|
526
|
+
console.log(chalk7.red("x package.json not found"));
|
|
527
|
+
issues++;
|
|
528
|
+
}
|
|
529
|
+
const tailwindConfigPath = join7(cwd, "tailwind.config.js");
|
|
530
|
+
if (existsSync7(tailwindConfigPath)) {
|
|
531
|
+
console.log(chalk7.green("\u2713 tailwind.config.js found"));
|
|
532
|
+
} else {
|
|
533
|
+
console.log(chalk7.yellow("\u26A0\uFE0F tailwind.config.js not found"));
|
|
534
|
+
issues++;
|
|
535
|
+
}
|
|
536
|
+
console.log("\nResult:");
|
|
537
|
+
if (issues === 0) {
|
|
538
|
+
console.log(chalk7.green("Everything looks good! \u2728"));
|
|
539
|
+
} else {
|
|
540
|
+
console.log(chalk7.yellow(`Found ${issues} issue(s).`));
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// src/commands/add.ts
|
|
545
|
+
import chalk8 from "chalk";
|
|
546
|
+
async function add(component) {
|
|
547
|
+
console.log(chalk8.bold(`Object UI Add: ${component}`));
|
|
548
|
+
console.log(chalk8.yellow("Feature not implemented yet."));
|
|
549
|
+
console.log(`This command will download the source code for ${component}Renderer to your project.`);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// src/commands/studio.ts
|
|
553
|
+
import chalk9 from "chalk";
|
|
554
|
+
async function studio() {
|
|
555
|
+
console.log(chalk9.bold("Starting Object UI Studio..."));
|
|
556
|
+
console.log(chalk9.yellow("Studio mode is experimental."));
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// src/commands/check.ts
|
|
560
|
+
import chalk10 from "chalk";
|
|
561
|
+
import { globSync } from "glob";
|
|
562
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
563
|
+
import { join as join8 } from "path";
|
|
564
|
+
async function check() {
|
|
565
|
+
console.log(chalk10.bold("Object UI Schema Check"));
|
|
566
|
+
const cwd = process.cwd();
|
|
567
|
+
const files = globSync("**/*.{json,yaml,yml}", {
|
|
568
|
+
cwd,
|
|
569
|
+
ignore: ["node_modules/**", "dist/**", ".git/**"]
|
|
570
|
+
});
|
|
571
|
+
console.log(`Analyzing ${files.length} files...`);
|
|
572
|
+
let errors = 0;
|
|
573
|
+
for (const file of files) {
|
|
574
|
+
try {
|
|
575
|
+
if (file.endsWith(".json")) {
|
|
576
|
+
JSON.parse(readFileSync2(join8(cwd, file), "utf-8"));
|
|
577
|
+
}
|
|
578
|
+
} catch (e) {
|
|
579
|
+
console.log(chalk10.red(`x Invalid JSON in ${file}: ${e.message}`));
|
|
580
|
+
errors++;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
if (errors === 0) {
|
|
584
|
+
console.log(chalk10.green("\u2713 All checks passed"));
|
|
585
|
+
} else {
|
|
586
|
+
console.log(chalk10.red(`Found ${errors} errors`));
|
|
587
|
+
process.exit(1);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// src/cli.ts
|
|
592
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
593
|
+
import { fileURLToPath } from "url";
|
|
594
|
+
import { dirname as dirname2, join as join9 } from "path";
|
|
595
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
596
|
+
var __dirname = dirname2(__filename);
|
|
597
|
+
var packageJson = JSON.parse(
|
|
598
|
+
readFileSync3(join9(__dirname, "../package.json"), "utf-8")
|
|
599
|
+
);
|
|
600
|
+
var program = new Command();
|
|
601
|
+
program.name("objectui").description("CLI tool for Object UI - Build applications from JSON schemas").version(packageJson.version);
|
|
602
|
+
program.command("serve").description("Start a development server with your JSON/YAML schema").argument("[schema]", "Path to JSON/YAML schema file", "app.json").option("-p, --port <port>", "Port to run the server on", "3000").option("-h, --host <host>", "Host to bind the server to", "localhost").action(async (schema, options) => {
|
|
603
|
+
try {
|
|
604
|
+
await serve(schema, options);
|
|
605
|
+
} catch (error) {
|
|
606
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
607
|
+
process.exit(1);
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
program.command("dev").description("Start development server (alias for serve)").argument("[schema]", "Path to JSON/YAML schema file", "app.json").option("-p, --port <port>", "Port to run the server on", "3000").option("-h, --host <host>", "Host to bind the server to", "localhost").option("--no-open", "Do not open browser automatically").action(async (schema, options) => {
|
|
611
|
+
try {
|
|
612
|
+
await dev(schema, options);
|
|
613
|
+
} catch (error) {
|
|
614
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
615
|
+
process.exit(1);
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
program.command("build").description("Build application for production").argument("[schema]", "Path to JSON/YAML schema file", "app.json").option("-o, --out-dir <dir>", "Output directory", "dist").option("--clean", "Clean output directory before build", false).action(async (schema, options) => {
|
|
619
|
+
try {
|
|
620
|
+
await buildApp(schema, options);
|
|
621
|
+
} catch (error) {
|
|
622
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
623
|
+
process.exit(1);
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
program.command("start").description("Start production server").option("-p, --port <port>", "Port to run the server on", "3000").option("-h, --host <host>", "Host to bind the server to", "0.0.0.0").option("-d, --dir <dir>", "Directory to serve", "dist").action(async (options) => {
|
|
627
|
+
try {
|
|
628
|
+
await start(options);
|
|
629
|
+
} catch (error) {
|
|
630
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
631
|
+
process.exit(1);
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
program.command("init").description("\u521D\u59CB\u5316\u65B0\u7684Object UI\u5E94\u7528 / Initialize a new Object UI application with sample schema").argument("[name]", "\u5E94\u7528\u540D\u79F0 / Application name", "my-app").option("-t, --template <template>", "\u4F7F\u7528\u7684\u6A21\u677F / Template to use (dashboard, form, simple)", "dashboard").action(async (name, options) => {
|
|
635
|
+
try {
|
|
636
|
+
await init(name, options);
|
|
637
|
+
} catch (error) {
|
|
638
|
+
console.error(chalk11.red("\u9519\u8BEF Error:"), error instanceof Error ? error.message : error);
|
|
639
|
+
process.exit(1);
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
program.command("lint").description("Lint the generated application code").option("--fix", "Automatically fix linting issues").action(async (options) => {
|
|
643
|
+
try {
|
|
644
|
+
await lint(options);
|
|
645
|
+
} catch (error) {
|
|
646
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
647
|
+
process.exit(1);
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
program.command("test").description("Run tests for the application").option("-w, --watch", "Run tests in watch mode").option("-c, --coverage", "Generate test coverage report").option("--ui", "Run tests with Vitest UI").action(async (options) => {
|
|
651
|
+
try {
|
|
652
|
+
await test(options);
|
|
653
|
+
} catch (error) {
|
|
654
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
655
|
+
process.exit(1);
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
program.command("generate").alias("g").description("Generate new resources (objects, pages, plugins)").argument("<type>", "Type of resource to generate (resource/object, page, plugin)").argument("<name>", "Name of the resource").action(async (type, name) => {
|
|
659
|
+
try {
|
|
660
|
+
await generate(type, name);
|
|
661
|
+
} catch (error) {
|
|
662
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
663
|
+
process.exit(1);
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
program.command("doctor").description("Diagnose and fix common issues").action(async () => {
|
|
667
|
+
try {
|
|
668
|
+
await doctor();
|
|
669
|
+
} catch (error) {
|
|
670
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
671
|
+
process.exit(1);
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
program.command("add").description("Add a new component renderer to your project").argument("<component>", "Component name (e.g. Input, Grid)").action(async (component) => {
|
|
675
|
+
try {
|
|
676
|
+
await add(component);
|
|
677
|
+
} catch (error) {
|
|
678
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
679
|
+
process.exit(1);
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
program.command("studio").description("Start the visual designer").action(async () => {
|
|
683
|
+
try {
|
|
684
|
+
await studio();
|
|
685
|
+
} catch (error) {
|
|
686
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
687
|
+
process.exit(1);
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
program.command("check").description("Validate schema files").action(async () => {
|
|
691
|
+
try {
|
|
692
|
+
await check();
|
|
693
|
+
} catch (error) {
|
|
694
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
695
|
+
process.exit(1);
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
program.command("showcase").description("Start the built-in showcase example").option("-p, --port <port>", "Port to run the server on", "3000").option("-h, --host <host>", "Host to bind the server to", "localhost").option("--no-open", "Do not open browser automatically").action(async (options) => {
|
|
699
|
+
try {
|
|
700
|
+
const showcaseSchema = join9(__dirname, "../../..", "examples", "showcase", "app.json");
|
|
701
|
+
await dev(showcaseSchema, options);
|
|
702
|
+
} catch (error) {
|
|
703
|
+
console.error(chalk11.red("Error:"), error instanceof Error ? error.message : error);
|
|
704
|
+
process.exit(1);
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
program.parse();
|
|
708
|
+
//# sourceMappingURL=cli.js.map
|