@object-ui/cli 17.3.0 → 17.6.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/dist/cli.js CHANGED
@@ -3,10 +3,12 @@ import {
3
3
  createTempApp,
4
4
  createTempAppWithRouting,
5
5
  init,
6
- parseSchemaFile,
7
- scanPagesDirectory,
6
+ isWorkspaceRoot,
7
+ prepareWorkspaceTempApp,
8
+ reportProjectSource,
9
+ resolveProjectSource,
8
10
  serve
9
- } from "./chunk-EV2DCI7W.js";
11
+ } from "./chunk-AP2INOE7.js";
10
12
 
11
13
  // src/cli.ts
12
14
  import { Command } from "commander";
@@ -15,87 +17,22 @@ import chalk14 from "chalk";
15
17
  // src/commands/dev.ts
16
18
  import { createServer } from "vite";
17
19
  import react from "@vitejs/plugin-react";
18
- import { existsSync, mkdirSync, unlinkSync, statSync } from "fs";
19
- import { join, resolve, dirname } from "path";
20
+ import { mkdirSync } from "fs";
21
+ import { join } from "path";
20
22
  import chalk from "chalk";
21
23
  import { execSync } from "child_process";
22
- import { createRequire } from "module";
23
24
  async function dev(schemaPath, options) {
24
25
  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
- const appJsonPath = join(cwd, "app.json");
53
- if (existsSync(appJsonPath)) {
54
- try {
55
- appConfig = parseSchemaFile(appJsonPath);
56
- console.log(chalk.blue("\u2699\uFE0F Loaded App Config from app.json"));
57
- } catch (_e) {
58
- console.warn("Failed to parse app.json config");
59
- }
60
- }
61
- }
62
- }
63
- const require2 = createRequire(join(cwd, "package.json"));
64
- let routes = [];
65
- let schema = null;
66
- let useFileSystemRouting = false;
67
- if (hasPagesDir) {
68
- console.log(chalk.blue(`\u{1F4C1} Using file-system routing from ${pagesDir}`));
69
- routes = scanPagesDirectory(pagesDir);
70
- useFileSystemRouting = true;
71
- if (routes.length === 0) {
72
- throw new Error(`No schema files found in ${pagesDir}`);
73
- }
74
- console.log(chalk.green(`\u2713 Found ${routes.length} route(s)`));
75
- routes.forEach((route) => {
76
- console.log(chalk.dim(` ${route.path} \u2192 ${route.filePath.replace(cwd, ".")}`));
77
- });
78
- } else {
79
- const fullSchemaPath = resolve(cwd, schemaPath);
80
- if (!existsSync(fullSchemaPath)) {
81
- throw new Error(`Schema file not found: ${schemaPath}
82
- Run 'objectui init' to create a sample schema.`);
83
- }
84
- console.log(chalk.blue("\u{1F4CB} Loading schema:"), chalk.cyan(schemaPath));
85
- try {
86
- schema = parseSchemaFile(fullSchemaPath);
87
- } catch (error) {
88
- throw new Error(`Invalid schema file: ${error instanceof Error ? error.message : error}`);
89
- }
90
- }
26
+ const source = resolveProjectSource(cwd, schemaPath);
27
+ reportProjectSource(source, cwd);
91
28
  const tmpDir = join(cwd, ".objectui-tmp");
92
29
  mkdirSync(tmpDir, { recursive: true });
93
- if (useFileSystemRouting) {
94
- createTempAppWithRouting(tmpDir, routes, appConfig);
30
+ if (source.mode === "routes") {
31
+ createTempAppWithRouting(tmpDir, source.routes, source.appConfig);
95
32
  } else {
96
- createTempApp(tmpDir, schema);
33
+ createTempApp(tmpDir, source.schema);
97
34
  }
98
- const isMonorepo = existsSync(join(cwd, "pnpm-workspace.yaml"));
35
+ const isMonorepo = isWorkspaceRoot(cwd);
99
36
  if (isMonorepo) {
100
37
  console.log(chalk.blue("\u{1F4E6} Detected monorepo - using root node_modules"));
101
38
  } else {
@@ -113,6 +50,10 @@ Run 'objectui init' to create a sample schema.`);
113
50
  }
114
51
  console.log(chalk.green("\u2713 Schema loaded successfully"));
115
52
  console.log(chalk.blue("\u{1F680} Starting development server...\n"));
53
+ if (isMonorepo) {
54
+ console.log(chalk.blue("\u{1F4E6} Detected monorepo - configuring workspace aliases"));
55
+ }
56
+ const workspaceConfig = isMonorepo ? await prepareWorkspaceTempApp(cwd, tmpDir) : {};
116
57
  const viteConfig = {
117
58
  root: tmpDir,
118
59
  server: {
@@ -124,51 +65,9 @@ Run 'objectui init' to create a sample schema.`);
124
65
  allow: [cwd]
125
66
  }
126
67
  },
127
- resolve: {
128
- alias: {}
129
- },
130
- plugins: [react()]
68
+ plugins: [react()],
69
+ ...workspaceConfig
131
70
  };
132
- if (isMonorepo) {
133
- console.log(chalk.blue("\u{1F4E6} Detected monorepo - configuring workspace aliases"));
134
- const postcssPath = join(tmpDir, "postcss.config.js");
135
- if (existsSync(postcssPath)) {
136
- unlinkSync(postcssPath);
137
- }
138
- viteConfig.resolve.alias = {
139
- "@object-ui/react": join(cwd, "packages/react/src/index.ts"),
140
- "@object-ui/components": join(cwd, "packages/components/src/index.ts"),
141
- "@object-ui/core": join(cwd, "packages/core/src/index.ts"),
142
- "@object-ui/types": join(cwd, "packages/types/src/index.ts"),
143
- "@object-ui/plugin-charts": join(cwd, "packages/plugin-charts/src/index.tsx"),
144
- "@object-ui/plugin-editor": join(cwd, "packages/plugin-editor/src/index.tsx"),
145
- "@object-ui/plugin-kanban": join(cwd, "packages/plugin-kanban/src/index.tsx"),
146
- "@object-ui/plugin-markdown": join(cwd, "packages/plugin-markdown/src/index.tsx"),
147
- "@object-ui/plugin-form": join(cwd, "packages/plugin-form/src/index.tsx"),
148
- "@object-ui/plugin-grid": join(cwd, "packages/plugin-grid/src/index.tsx"),
149
- "@object-ui/plugin-view": join(cwd, "packages/plugin-view/src/index.tsx")
150
- };
151
- try {
152
- const lucidePath = require2.resolve("lucide-react", { paths: [join(cwd, "packages/components")] });
153
- viteConfig.resolve.alias["lucide-react"] = lucidePath;
154
- } catch (e) {
155
- console.warn("\u26A0\uFE0F Could not resolve lucide-react automatically:", e);
156
- }
157
- try {
158
- const tailwindcss = require2("tailwindcss");
159
- const autoprefixer = require2("autoprefixer");
160
- viteConfig.css = {
161
- postcss: {
162
- plugins: [
163
- tailwindcss(join(tmpDir, "tailwind.config.js")),
164
- autoprefixer()
165
- ]
166
- }
167
- };
168
- } catch (_e) {
169
- console.warn(chalk.yellow("\u26A0\uFE0F Failed to load PostCSS plugins from root node_modules. Styles might not work correctly."));
170
- }
171
- }
172
71
  const server = await createServer(viteConfig);
173
72
  await server.listen();
174
73
  const { port, host } = server.config.server;
@@ -186,62 +85,47 @@ Run 'objectui init' to create a sample schema.`);
186
85
  // src/commands/build.ts
187
86
  import { build as viteBuild } from "vite";
188
87
  import react2 from "@vitejs/plugin-react";
189
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, cpSync, rmSync } from "fs";
190
- import { join as join2, resolve as resolve2 } from "path";
88
+ import { existsSync, mkdirSync as mkdirSync2, cpSync, rmSync } from "fs";
89
+ import { join as join2, resolve } from "path";
191
90
  import chalk2 from "chalk";
192
91
  import { execSync as execSync2 } from "child_process";
193
92
  async function buildApp(schemaPath, options) {
194
93
  const cwd = process.cwd();
195
94
  const outDir = options.outDir || "dist";
196
- const outputPath = resolve2(cwd, outDir);
95
+ const outputPath = resolve(cwd, outDir);
197
96
  console.log(chalk2.blue("\u{1F528} Building application for production..."));
198
97
  console.log();
199
- const pagesDir = join2(cwd, "pages");
200
- const hasPagesDir = existsSync2(pagesDir);
201
- let routes = [];
202
- let schema = null;
203
- let useFileSystemRouting = false;
204
- if (hasPagesDir) {
205
- console.log(chalk2.blue("\u{1F4C1} Using file-system routing"));
206
- routes = scanPagesDirectory(pagesDir);
207
- useFileSystemRouting = true;
208
- if (routes.length === 0) {
209
- throw new Error("No schema files found in pages/ directory");
210
- }
211
- console.log(chalk2.green(`\u2713 Found ${routes.length} route(s)`));
212
- } else {
213
- const fullSchemaPath = resolve2(cwd, schemaPath);
214
- if (!existsSync2(fullSchemaPath)) {
215
- throw new Error(`Schema file not found: ${schemaPath}
216
- Run 'objectui init' to create a sample schema.`);
217
- }
218
- console.log(chalk2.blue("\u{1F4CB} Loading schema:"), chalk2.cyan(schemaPath));
219
- try {
220
- schema = parseSchemaFile(fullSchemaPath);
221
- } catch (error) {
222
- throw new Error(`Invalid schema file: ${error instanceof Error ? error.message : error}`);
223
- }
224
- }
98
+ const source = resolveProjectSource(cwd, schemaPath);
99
+ reportProjectSource(source, cwd);
225
100
  const tmpDir = join2(cwd, ".objectui-tmp");
226
101
  mkdirSync2(tmpDir, { recursive: true });
227
- if (useFileSystemRouting) {
228
- createTempAppWithRouting(tmpDir, routes);
102
+ if (source.mode === "routes") {
103
+ createTempAppWithRouting(tmpDir, source.routes, source.appConfig);
229
104
  } else {
230
- createTempApp(tmpDir, schema);
105
+ createTempApp(tmpDir, source.schema);
231
106
  }
232
- console.log(chalk2.blue("\u{1F4E6} Installing dependencies..."));
233
- try {
234
- execSync2("npm install --silent --prefer-offline", {
235
- cwd: tmpDir,
236
- stdio: "pipe"
237
- });
238
- console.log(chalk2.green("\u2713 Dependencies installed"));
239
- } catch {
240
- throw new Error("Failed to install dependencies. Please check your internet connection and try again.");
107
+ const isMonorepo = isWorkspaceRoot(cwd);
108
+ if (isMonorepo) {
109
+ console.log(chalk2.blue("\u{1F4E6} Detected monorepo - using root node_modules"));
110
+ } else {
111
+ console.log(chalk2.blue("\u{1F4E6} Installing dependencies..."));
112
+ try {
113
+ execSync2("npm install --silent --prefer-offline", {
114
+ cwd: tmpDir,
115
+ stdio: "pipe"
116
+ });
117
+ console.log(chalk2.green("\u2713 Dependencies installed"));
118
+ } catch {
119
+ throw new Error("Failed to install dependencies. Please check your internet connection and try again.");
120
+ }
121
+ }
122
+ if (isMonorepo) {
123
+ console.log(chalk2.blue("\u{1F4E6} Detected monorepo - configuring workspace aliases"));
241
124
  }
125
+ const workspaceConfig = isMonorepo ? await prepareWorkspaceTempApp(cwd, tmpDir) : {};
242
126
  console.log(chalk2.blue("\u2699\uFE0F Building with Vite..."));
243
127
  console.log();
244
- if (options.clean && existsSync2(outputPath)) {
128
+ if (options.clean && existsSync(outputPath)) {
245
129
  console.log(chalk2.dim(` Cleaning ${outDir}/ directory...`));
246
130
  rmSync(outputPath, { recursive: true, force: true });
247
131
  }
@@ -254,7 +138,8 @@ Run 'objectui init' to create a sample schema.`);
254
138
  reportCompressedSize: true
255
139
  },
256
140
  plugins: [react2()],
257
- logLevel: "info"
141
+ logLevel: "info",
142
+ ...workspaceConfig
258
143
  });
259
144
  mkdirSync2(outputPath, { recursive: true });
260
145
  cpSync(join2(tmpDir, "dist"), outputPath, { recursive: true });
@@ -274,21 +159,21 @@ Run 'objectui init' to create a sample schema.`);
274
159
  // src/commands/start.ts
275
160
  import express from "express";
276
161
  import rateLimit from "express-rate-limit";
277
- import { existsSync as existsSync3 } from "fs";
278
- import { join as join3, resolve as resolve3 } from "path";
162
+ import { existsSync as existsSync2 } from "fs";
163
+ import { join as join3, resolve as resolve2 } from "path";
279
164
  import chalk3 from "chalk";
280
165
  async function start(options) {
281
166
  const cwd = process.cwd();
282
167
  const distDir = options.dir || "dist";
283
- const distPath = resolve3(cwd, distDir);
284
- if (!existsSync3(distPath)) {
168
+ const distPath = resolve2(cwd, distDir);
169
+ if (!existsSync2(distPath)) {
285
170
  throw new Error(
286
171
  `Build directory not found: ${distDir}
287
172
  Run 'objectui build' first to create a production build.`
288
173
  );
289
174
  }
290
175
  const indexPath = join3(distPath, "index.html");
291
- if (!existsSync3(indexPath)) {
176
+ if (!existsSync2(indexPath)) {
292
177
  throw new Error(
293
178
  `index.html not found in ${distDir}/
294
179
  Make sure you have a valid production build.`
@@ -329,14 +214,14 @@ Make sure you have a valid production build.`
329
214
 
330
215
  // src/commands/lint.ts
331
216
  import { execSync as execSync3 } from "child_process";
332
- import { existsSync as existsSync4 } from "fs";
217
+ import { existsSync as existsSync3 } from "fs";
333
218
  import { join as join4 } from "path";
334
219
  import chalk4 from "chalk";
335
220
  async function lint(options) {
336
221
  const cwd = process.cwd();
337
222
  console.log(chalk4.blue("\u{1F50D} Running linter...\n"));
338
223
  const tmpDir = join4(cwd, ".objectui-tmp");
339
- const hasTempApp = existsSync4(tmpDir);
224
+ const hasTempApp = existsSync3(tmpDir);
340
225
  if (!hasTempApp) {
341
226
  throw new Error(
342
227
  "No Object UI application found. Run 'objectui dev' first to generate the application."
@@ -344,7 +229,7 @@ async function lint(options) {
344
229
  }
345
230
  const packageJsonPath = join4(tmpDir, "package.json");
346
231
  const nodeModulesPath = join4(tmpDir, "node_modules");
347
- if (!existsSync4(packageJsonPath) || !existsSync4(nodeModulesPath)) {
232
+ if (!existsSync3(packageJsonPath) || !existsSync3(nodeModulesPath)) {
348
233
  throw new Error(
349
234
  "Dependencies not installed. Run 'objectui dev' first to set up the application."
350
235
  );
@@ -374,14 +259,14 @@ async function lint(options) {
374
259
 
375
260
  // src/commands/test.ts
376
261
  import { execSync as execSync4 } from "child_process";
377
- import { existsSync as existsSync5 } from "fs";
262
+ import { existsSync as existsSync4 } from "fs";
378
263
  import { join as join5 } from "path";
379
264
  import chalk5 from "chalk";
380
265
  async function test(options) {
381
266
  const cwd = process.cwd();
382
267
  console.log(chalk5.blue("\u{1F9EA} Running tests...\n"));
383
268
  const tmpDir = join5(cwd, ".objectui-tmp");
384
- const hasTempApp = existsSync5(tmpDir);
269
+ const hasTempApp = existsSync4(tmpDir);
385
270
  if (!hasTempApp) {
386
271
  throw new Error(
387
272
  "No Object UI application found. Run 'objectui dev' first to generate the application."
@@ -389,7 +274,7 @@ async function test(options) {
389
274
  }
390
275
  const packageJsonPath = join5(tmpDir, "package.json");
391
276
  const nodeModulesPath = join5(tmpDir, "node_modules");
392
- if (!existsSync5(packageJsonPath) || !existsSync5(nodeModulesPath)) {
277
+ if (!existsSync4(packageJsonPath) || !existsSync4(nodeModulesPath)) {
393
278
  throw new Error(
394
279
  "Dependencies not installed. Run 'objectui dev' first to set up the application."
395
280
  );
@@ -427,7 +312,7 @@ async function test(options) {
427
312
 
428
313
  // src/commands/generate.ts
429
314
  import chalk6 from "chalk";
430
- import { existsSync as existsSync6, mkdirSync as mkdirSync3, writeFileSync } from "fs";
315
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, writeFileSync } from "fs";
431
316
  import { join as join6 } from "path";
432
317
  async function generate(type, name) {
433
318
  const cwd = process.cwd();
@@ -450,10 +335,10 @@ async function generate(type, name) {
450
335
  }
451
336
  function generateResource(cwd, name) {
452
337
  const dir = join6(cwd, "objects");
453
- if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
338
+ if (!existsSync5(dir)) mkdirSync3(dir, { recursive: true });
454
339
  const fileName = `${name.toLowerCase()}.json`;
455
340
  const filePath = join6(dir, fileName);
456
- if (existsSync6(filePath)) {
341
+ if (existsSync5(filePath)) {
457
342
  console.log(chalk6.yellow(`Object ${name} already exists at ${filePath}`));
458
343
  return;
459
344
  }
@@ -468,10 +353,10 @@ function generateResource(cwd, name) {
468
353
  }
469
354
  function generatePage(cwd, name) {
470
355
  const dir = join6(cwd, "pages");
471
- if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
356
+ if (!existsSync5(dir)) mkdirSync3(dir, { recursive: true });
472
357
  const fileName = `${name.toLowerCase()}.json`;
473
358
  const filePath = join6(dir, fileName);
474
- if (existsSync6(filePath)) {
359
+ if (existsSync5(filePath)) {
475
360
  console.log(chalk6.yellow(`Page ${name} already exists at ${filePath}`));
476
361
  return;
477
362
  }
@@ -490,7 +375,7 @@ function generatePage(cwd, name) {
490
375
  }
491
376
  function generatePlugin(cwd, name) {
492
377
  const dir = join6(cwd, "plugins", name);
493
- if (existsSync6(dir)) {
378
+ if (existsSync5(dir)) {
494
379
  console.log(chalk6.yellow(`Plugin ${name} already exists`));
495
380
  return;
496
381
  }
@@ -509,95 +394,223 @@ export const ${name}Plugin = {
509
394
 
510
395
  // src/commands/doctor.ts
511
396
  import chalk7 from "chalk";
512
- import { existsSync as existsSync7, readFileSync } from "fs";
513
- import { join as join7 } from "path";
514
- async function doctor() {
515
- console.log(chalk7.bold("Object UI Doctor"));
516
- console.log("Diagnosis in progress...\n");
517
- const cwd = process.cwd();
518
- let issues = 0;
397
+ import { existsSync as existsSync6, readFileSync } from "fs";
398
+ import { dirname, join as join7, resolve as resolvePath } from "path";
399
+ var CSS_ENTRY_CANDIDATES = [
400
+ "src/index.css",
401
+ "src/main.css",
402
+ "src/styles.css",
403
+ "src/style.css",
404
+ "src/app.css",
405
+ "src/global.css",
406
+ "src/globals.css",
407
+ "app/globals.css",
408
+ "app/global.css",
409
+ "styles/globals.css",
410
+ "index.css",
411
+ "styles.css"
412
+ ];
413
+ var TAILWIND_CONFIG_CANDIDATES = [
414
+ "tailwind.config.js",
415
+ "tailwind.config.cjs",
416
+ "tailwind.config.mjs",
417
+ "tailwind.config.ts"
418
+ ];
419
+ var POSTCSS_CONFIG_CANDIDATES = [
420
+ "postcss.config.js",
421
+ "postcss.config.cjs",
422
+ "postcss.config.mjs",
423
+ "postcss.config.ts"
424
+ ];
425
+ var V4_CSS_IMPORT = /@import\s+["']tailwindcss["']/;
426
+ var V3_CSS_DIRECTIVE = /@tailwind\s+(?:base|components|utilities|screens|variants)\b/;
427
+ var CSS_SOURCE_DIRECTIVE = /@source\s+["']/;
428
+ var CSS_CONFIG_DIRECTIVE = /@config\s+["']/;
429
+ var V4_POSTCSS_PLUGIN = /@tailwindcss\/postcss/;
430
+ var V3_POSTCSS_PLUGIN = /["']tailwindcss["']|(?:^|[{,\s])tailwindcss\s*:/m;
431
+ function readIfExists(path) {
432
+ try {
433
+ return existsSync6(path) ? readFileSync(path, "utf-8") : null;
434
+ } catch {
435
+ return null;
436
+ }
437
+ }
438
+ function findFile(cwd, candidates) {
439
+ for (const rel of candidates) {
440
+ const abs = join7(cwd, rel);
441
+ if (existsSync6(abs)) return abs;
442
+ }
443
+ return null;
444
+ }
445
+ function majorOf(range) {
446
+ const match = /(\d+)/.exec(range);
447
+ if (!match) return null;
448
+ const major = Number.parseInt(match[1], 10);
449
+ return Number.isNaN(major) ? null : major;
450
+ }
451
+ function isInstalledFrom(cwd, specifier) {
452
+ let dir = resolvePath(cwd);
453
+ for (; ; ) {
454
+ if (existsSync6(join7(dir, "node_modules", ...specifier.split("/")))) return true;
455
+ const parent = dirname(dir);
456
+ if (parent === dir) return false;
457
+ dir = parent;
458
+ }
459
+ }
460
+ function runDiagnostics(cwd) {
461
+ const results = [];
462
+ const ok = (id, message) => {
463
+ results.push({ id, level: "ok", message });
464
+ };
465
+ const warn = (id, message) => {
466
+ results.push({ id, level: "warn", message });
467
+ };
468
+ const error = (id, message) => {
469
+ results.push({ id, level: "error", message });
470
+ };
519
471
  const pkgPath = join7(cwd, "package.json");
520
- if (existsSync7(pkgPath)) {
472
+ const pkgRaw = readIfExists(pkgPath);
473
+ let pkg = null;
474
+ if (pkgRaw === null) {
475
+ error("package-json-missing", "package.json not found");
476
+ } else {
521
477
  try {
522
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
523
- const reactVer = pkg.dependencies?.react || pkg.devDependencies?.react;
524
- if (reactVer) {
525
- console.log(chalk7.green("\u2713 React installed"));
478
+ pkg = JSON.parse(pkgRaw);
479
+ } catch {
480
+ error("package-json-unreadable", "Failed to parse package.json");
481
+ }
482
+ }
483
+ const deps = pkg ? { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} } : {};
484
+ if (pkg) {
485
+ if (deps.react) {
486
+ ok("react-installed", "React installed");
487
+ } else {
488
+ warn("react-missing", "React not found in dependencies");
489
+ }
490
+ }
491
+ const tailwindRange = pkg ? deps.tailwindcss : void 0;
492
+ if (pkg && !tailwindRange) {
493
+ warn("tailwind-missing", "Tailwind CSS not found in dependencies");
494
+ }
495
+ if (tailwindRange) {
496
+ const major = majorOf(tailwindRange);
497
+ if (major !== null && major < 4) {
498
+ warn(
499
+ "tailwind-major-legacy",
500
+ `Tailwind CSS ${tailwindRange} detected \u2014 ObjectUI targets Tailwind 4. Upgrade with \`npx @tailwindcss/upgrade\`, then move configuration into your CSS entry (\`@import 'tailwindcss'\`, \`@theme\`, \`@source\`).`
501
+ );
502
+ } else {
503
+ ok("tailwind-installed", `Tailwind CSS ${tailwindRange} installed`);
504
+ }
505
+ if (deps["@tailwindcss/postcss"]) {
506
+ ok("tailwind-postcss-declared", "@tailwindcss/postcss declared");
507
+ } else if (isInstalledFrom(cwd, "@tailwindcss/postcss")) {
508
+ ok(
509
+ "tailwind-postcss-installed",
510
+ "@tailwindcss/postcss installed (provided by the workspace)"
511
+ );
512
+ } else {
513
+ error(
514
+ "tailwind-postcss-missing",
515
+ "Tailwind CSS 4 needs @tailwindcss/postcss, which is neither declared nor installed here. v4 moved the PostCSS plugin out of `tailwindcss` into its own package; without it PostCSS fails to load and no styles are emitted. Install it: `npm i -D @tailwindcss/postcss`."
516
+ );
517
+ }
518
+ const postcssConfigPath = findFile(cwd, POSTCSS_CONFIG_CANDIDATES);
519
+ if (postcssConfigPath) {
520
+ const postcssConfig = readIfExists(postcssConfigPath) ?? "";
521
+ const hasV4Plugin = V4_POSTCSS_PLUGIN.test(postcssConfig);
522
+ const hasV3Plugin = V3_POSTCSS_PLUGIN.test(postcssConfig);
523
+ if (hasV3Plugin) {
524
+ error(
525
+ "postcss-plugin-v3",
526
+ "PostCSS config names `tailwindcss` as a plugin \u2014 the Tailwind 3 spelling. In v4 that entry resolves to a shim whose only job is to throw. Replace it with `'@tailwindcss/postcss': {}`."
527
+ );
528
+ } else if (hasV4Plugin) {
529
+ ok("postcss-plugin-v4", "PostCSS config uses @tailwindcss/postcss");
526
530
  } else {
527
- console.log(chalk7.yellow("\u26A0\uFE0F React not found in dependencies"));
528
- issues++;
531
+ warn(
532
+ "postcss-plugin-absent",
533
+ "PostCSS config does not register a Tailwind plugin. Add `'@tailwindcss/postcss': {}` so Tailwind runs during the build."
534
+ );
529
535
  }
530
- const tailwindVer = pkg.dependencies?.tailwindcss || pkg.devDependencies?.tailwindcss;
531
- if (tailwindVer) {
532
- console.log(chalk7.green("\u2713 Tailwind CSS installed"));
533
- } else {
534
- console.log(chalk7.yellow("\u26A0\uFE0F Tailwind CSS not found"));
535
- issues++;
536
+ }
537
+ const cssEntries = CSS_ENTRY_CANDIDATES.map((rel) => ({
538
+ rel,
539
+ content: readIfExists(join7(cwd, rel))
540
+ })).filter((entry) => entry.content !== null);
541
+ const importsTailwind = cssEntries.some((entry) => V4_CSS_IMPORT.test(entry.content));
542
+ const usesV3Directives = cssEntries.some((entry) => V3_CSS_DIRECTIVE.test(entry.content));
543
+ const declaresSource = cssEntries.some((entry) => CSS_SOURCE_DIRECTIVE.test(entry.content));
544
+ const optsIntoJsConfig = cssEntries.some((entry) => CSS_CONFIG_DIRECTIVE.test(entry.content));
545
+ if (cssEntries.length === 0) {
546
+ } else if (importsTailwind) {
547
+ ok("css-entry-v4-import", "CSS entry runs `@import 'tailwindcss'`");
548
+ if (declaresSource) {
549
+ ok("css-entry-source", "CSS entry declares `@source` scanning paths");
536
550
  }
537
- } catch (e) {
538
- console.log(chalk7.red("x Failed to read package.json"));
539
- issues++;
551
+ } else if (usesV3Directives) {
552
+ error(
553
+ "css-entry-v3-directives",
554
+ "CSS entry still uses the Tailwind 3 `@tailwind base/components/utilities` directives. Tailwind 4 replaces all three with a single `@import 'tailwindcss';`."
555
+ );
556
+ } else {
557
+ warn(
558
+ "css-entry-no-tailwind",
559
+ `No CSS entry runs \`@import 'tailwindcss'\`, so Tailwind never starts. Checked: ${cssEntries.map((entry) => entry.rel).join(", ")}.`
560
+ );
540
561
  }
541
- } else {
542
- console.log(chalk7.red("x package.json not found"));
543
- issues++;
544
- }
545
- const tailwindConfigPath = join7(cwd, "tailwind.config.js");
546
- const tailwindTsPath = join7(cwd, "tailwind.config.ts");
547
- if (existsSync7(tailwindConfigPath) || existsSync7(tailwindTsPath)) {
548
- const configFile = existsSync7(tailwindConfigPath) ? "tailwind.config.js" : "tailwind.config.ts";
549
- const configPath = existsSync7(tailwindConfigPath) ? tailwindConfigPath : tailwindTsPath;
550
- console.log(chalk7.green(`\u2713 ${configFile} found`));
551
- try {
552
- const configContent = readFileSync(configPath, "utf-8");
553
- if (configContent.includes("content") && (configContent.includes("./src") || configContent.includes("./app") || configContent.includes("./pages"))) {
554
- console.log(chalk7.green("\u2713 Tailwind content paths configured"));
562
+ const tailwindConfigPath = findFile(cwd, TAILWIND_CONFIG_CANDIDATES);
563
+ if (tailwindConfigPath && !optsIntoJsConfig) {
564
+ const rel = tailwindConfigPath.slice(cwd.length + 1);
565
+ warn(
566
+ "tailwind-config-inert",
567
+ `${rel} exists but nothing opts into it \u2014 Tailwind 4 ignores a JS config unless a stylesheet declares \`@config\`. Anything it sets (theme, content/@source paths, plugins) has no effect today. Either delete it and move the settings into your CSS entry, or add \`@config '${rel}';\` there.`
568
+ );
569
+ } else if (tailwindConfigPath) {
570
+ ok("tailwind-config-active", "JS Tailwind config is loaded via `@config`");
571
+ }
572
+ }
573
+ if (existsSync6(join7(cwd, "tsconfig.json"))) {
574
+ ok("tsconfig-found", "tsconfig.json found");
575
+ const tsRange = deps.typescript;
576
+ if (tsRange) {
577
+ const major = majorOf(tsRange);
578
+ if (major !== null && major < 5) {
579
+ warn("typescript-legacy", `TypeScript ${tsRange} detected \u2014 version 5.0+ recommended`);
555
580
  } else {
556
- console.log(chalk7.yellow("\u26A0\uFE0F Tailwind content paths may not be configured. Ensure your content array includes source directories."));
557
- issues++;
581
+ ok("typescript-version", `TypeScript ${tsRange} (5.0+ required)`);
558
582
  }
559
- } catch (_e) {
560
583
  }
561
584
  } else {
562
- console.log(chalk7.yellow("\u26A0\uFE0F tailwind.config.js not found"));
563
- issues++;
585
+ warn("tsconfig-missing", "tsconfig.json not found");
564
586
  }
565
- const tsConfigPath = join7(cwd, "tsconfig.json");
566
- if (existsSync7(tsConfigPath)) {
567
- console.log(chalk7.green("\u2713 tsconfig.json found"));
568
- try {
569
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
570
- const tsVer = pkg.devDependencies?.typescript || pkg.dependencies?.typescript;
571
- if (tsVer) {
572
- const majorVer = parseInt(tsVer.replace(/[^0-9.]/g, "").split(".")[0], 10);
573
- if (majorVer >= 5) {
574
- console.log(chalk7.green(`\u2713 TypeScript ${tsVer} (5.0+ required)`));
575
- } else {
576
- console.log(chalk7.yellow(`\u26A0\uFE0F TypeScript ${tsVer} detected \u2014 version 5.0+ recommended`));
577
- issues++;
578
- }
579
- }
580
- } catch (_e) {
587
+ if (pkg) {
588
+ if (deps["@object-ui/react"] && !deps.react) {
589
+ warn("peer-react", "@object-ui/react requires react as a peer dependency");
590
+ }
591
+ if (deps["@object-ui/components"] && !deps.tailwindcss) {
592
+ warn("peer-tailwind", "@object-ui/components requires tailwindcss as a peer dependency");
581
593
  }
582
- } else {
583
- console.log(chalk7.yellow("\u26A0\uFE0F tsconfig.json not found"));
584
- issues++;
585
594
  }
586
- if (existsSync7(pkgPath)) {
587
- try {
588
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
589
- const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
590
- if (allDeps["@object-ui/react"] && !allDeps["react"]) {
591
- console.log(chalk7.yellow("\u26A0\uFE0F @object-ui/react requires react as a peer dependency"));
592
- issues++;
593
- }
594
- if (allDeps["@object-ui/components"] && !allDeps["tailwindcss"]) {
595
- console.log(chalk7.yellow("\u26A0\uFE0F @object-ui/components requires tailwindcss as a peer dependency"));
596
- issues++;
597
- }
598
- } catch (_e) {
595
+ return results;
596
+ }
597
+ function countIssues(results) {
598
+ return results.filter((result) => result.level !== "ok").length;
599
+ }
600
+ async function doctor() {
601
+ console.log(chalk7.bold("Object UI Doctor"));
602
+ console.log("Diagnosis in progress...\n");
603
+ const results = runDiagnostics(process.cwd());
604
+ for (const result of results) {
605
+ if (result.level === "ok") {
606
+ console.log(chalk7.green(`\u2713 ${result.message}`));
607
+ } else if (result.level === "warn") {
608
+ console.log(chalk7.yellow(`\u26A0\uFE0F ${result.message}`));
609
+ } else {
610
+ console.log(chalk7.red(`x ${result.message}`));
599
611
  }
600
612
  }
613
+ const issues = countIssues(results);
601
614
  console.log("\nResult:");
602
615
  if (issues === 0) {
603
616
  console.log(chalk7.green("Everything looks good! \u2728"));
@@ -617,8 +630,8 @@ async function add(component) {
617
630
  // src/commands/studio.ts
618
631
  import chalk9 from "chalk";
619
632
  import { spawn } from "child_process";
620
- import { existsSync as existsSync8 } from "fs";
621
- import { join as join8, resolve as resolve4, dirname as dirname2 } from "path";
633
+ import { existsSync as existsSync7 } from "fs";
634
+ import { join as join8, resolve as resolve3, dirname as dirname2 } from "path";
622
635
  import { fileURLToPath } from "url";
623
636
  async function studio() {
624
637
  console.log(chalk9.bold("\n\u{1F3A8} Starting ObjectUI Studio...\n"));
@@ -627,12 +640,12 @@ async function studio() {
627
640
  const __dirname3 = dirname2(__filename3);
628
641
  const candidates = [
629
642
  join8(cwd, "apps/console"),
630
- resolve4(__dirname3, "../../apps/console"),
631
- resolve4(__dirname3, "../../../apps/console")
643
+ resolve3(__dirname3, "../../apps/console"),
644
+ resolve3(__dirname3, "../../../apps/console")
632
645
  ];
633
646
  let consolePath = null;
634
647
  for (const candidate of candidates) {
635
- if (existsSync8(join8(candidate, "package.json"))) {
648
+ if (existsSync7(join8(candidate, "package.json"))) {
636
649
  consolePath = candidate;
637
650
  break;
638
651
  }
@@ -664,41 +677,735 @@ import chalk10 from "chalk";
664
677
  import { globSync } from "glob";
665
678
  import { readFileSync as readFileSync2 } from "fs";
666
679
  import { join as join9 } from "path";
667
- async function check() {
680
+ import { parse as parseJsonc, printParseErrorCode } from "jsonc-parser";
681
+
682
+ // src/utils/known-schema-types.ts
683
+ var KNOWN_SCHEMA_TYPES = [
684
+ "a",
685
+ "abbr",
686
+ "accordion",
687
+ "action:bar",
688
+ "action:button",
689
+ "action:group",
690
+ "action:icon",
691
+ "action:menu",
692
+ "address",
693
+ "advanced-chart",
694
+ "ai-form-assist",
695
+ "ai-recommendations",
696
+ "ai:feedback",
697
+ "ai:input",
698
+ "ai:suggestion",
699
+ "alert",
700
+ "alert-dialog",
701
+ "app",
702
+ "app-creation-wizard",
703
+ "app-schema-renderer",
704
+ "app-shell:cloud-connection:panel",
705
+ "app-shell:cloud:ai-model-status",
706
+ "app-shell:cloud:onboarding-next",
707
+ "app-shell:marketplace:installed-list",
708
+ "app-shell:mcp:connect-agent",
709
+ "app:launcher",
710
+ "area-chart",
711
+ "article",
712
+ "aside",
713
+ "aspect-ratio",
714
+ "auto_number",
715
+ "avatar",
716
+ "b",
717
+ "badge",
718
+ "bar-chart",
719
+ "blockquote",
720
+ "boolean",
721
+ "br",
722
+ "branding-editor",
723
+ "breadcrumb",
724
+ "button",
725
+ "button-group",
726
+ "calendar",
727
+ "calendar-view",
728
+ "card",
729
+ "carousel",
730
+ "chart",
731
+ "chart:bar",
732
+ "chatbot",
733
+ "chatbot-enhanced",
734
+ "chatbot-floating",
735
+ "checkbox",
736
+ "checkboxes",
737
+ "cite",
738
+ "cloud-connection:panel",
739
+ "cloud:ai-model-status",
740
+ "cloud:onboarding-next",
741
+ "code",
742
+ "code-editor",
743
+ "collapsible",
744
+ "color",
745
+ "combobox",
746
+ "command",
747
+ "container",
748
+ "context-menu",
749
+ "currency",
750
+ "dashboard",
751
+ "dashboard-editor",
752
+ "dashboard-grid",
753
+ "data-model-designer",
754
+ "data-table",
755
+ "date",
756
+ "date-picker",
757
+ "datetime",
758
+ "dd",
759
+ "del",
760
+ "detail",
761
+ "detail-section",
762
+ "detail-view",
763
+ "dialog",
764
+ "div",
765
+ "dl",
766
+ "donut-chart",
767
+ "drawer",
768
+ "dropdown-menu",
769
+ "dt",
770
+ "element:button",
771
+ "element:definition-list",
772
+ "element:divider",
773
+ "element:image",
774
+ "element:metadata_viewer",
775
+ "element:number",
776
+ "element:record_picker",
777
+ "element:repeater",
778
+ "element:text",
779
+ "element:text_input",
780
+ "em",
781
+ "email",
782
+ "embeddable-form",
783
+ "empty",
784
+ "field-designer",
785
+ "field:address",
786
+ "field:audio",
787
+ "field:auto_number",
788
+ "field:avatar",
789
+ "field:boolean",
790
+ "field:checkboxes",
791
+ "field:code",
792
+ "field:color",
793
+ "field:currency",
794
+ "field:date",
795
+ "field:datetime",
796
+ "field:duration",
797
+ "field:email",
798
+ "field:file",
799
+ "field:filter-condition",
800
+ "field:formula",
801
+ "field:geolocation",
802
+ "field:grid",
803
+ "field:html",
804
+ "field:image",
805
+ "field:json",
806
+ "field:location",
807
+ "field:lookup",
808
+ "field:markdown",
809
+ "field:master_detail",
810
+ "field:multiselect",
811
+ "field:number",
812
+ "field:object",
813
+ "field:object-ref",
814
+ "field:password",
815
+ "field:percent",
816
+ "field:permission-facet-link",
817
+ "field:phone",
818
+ "field:progress",
819
+ "field:qrcode",
820
+ "field:radio",
821
+ "field:rating",
822
+ "field:recipient-picker",
823
+ "field:richtext",
824
+ "field:select",
825
+ "field:signature",
826
+ "field:slider",
827
+ "field:summary",
828
+ "field:tags",
829
+ "field:text",
830
+ "field:textarea",
831
+ "field:time",
832
+ "field:tree",
833
+ "field:url",
834
+ "field:user",
835
+ "field:vector",
836
+ "field:video",
837
+ "figcaption",
838
+ "figure",
839
+ "file",
840
+ "file-upload",
841
+ "filter-builder",
842
+ "filter-ui",
843
+ "flex",
844
+ "footer",
845
+ "form",
846
+ "form-analytics",
847
+ "formula",
848
+ "gantt",
849
+ "geolocation",
850
+ "global:notifications",
851
+ "global:search",
852
+ "grid",
853
+ "h1",
854
+ "h2",
855
+ "h3",
856
+ "h4",
857
+ "h5",
858
+ "h6",
859
+ "header",
860
+ "header-bar",
861
+ "home",
862
+ "hover-card",
863
+ "hr",
864
+ "html",
865
+ "i",
866
+ "icon",
867
+ "image",
868
+ "img",
869
+ "import-wizard",
870
+ "input",
871
+ "input-otp",
872
+ "ins",
873
+ "kanban",
874
+ "kanban-enhanced",
875
+ "kanban-ui",
876
+ "kbd",
877
+ "label",
878
+ "layout:app-schema-renderer",
879
+ "layout:navigation-renderer",
880
+ "layout:page-header",
881
+ "layout:page:card",
882
+ "layout:responsive-grid",
883
+ "li",
884
+ "line-chart",
885
+ "list",
886
+ "list-view",
887
+ "loading",
888
+ "location",
889
+ "lookup",
890
+ "main",
891
+ "map",
892
+ "mark",
893
+ "markdown",
894
+ "marketplace:installed-list",
895
+ "master_detail",
896
+ "mcp:connect-agent",
897
+ "menubar",
898
+ "metric",
899
+ "metric-card",
900
+ "multiselect",
901
+ "nav",
902
+ "nav:breadcrumb",
903
+ "nav:menu",
904
+ "navigation-designer",
905
+ "navigation-menu",
906
+ "navigation-renderer",
907
+ "nl-query",
908
+ "number",
909
+ "object",
910
+ "object-calendar",
911
+ "object-chart",
912
+ "object-data-table",
913
+ "object-form",
914
+ "object-gallery",
915
+ "object-gantt",
916
+ "object-grid",
917
+ "object-kanban",
918
+ "object-manager",
919
+ "object-map",
920
+ "object-master-detail-form",
921
+ "object-metric",
922
+ "object-pivot",
923
+ "object-timeline",
924
+ "object-tree",
925
+ "object-view",
926
+ "ol",
927
+ "p",
928
+ "page",
929
+ "page-designer",
930
+ "page-header",
931
+ "page:accordion",
932
+ "page:card",
933
+ "page:footer",
934
+ "page:header",
935
+ "page:section",
936
+ "page:sidebar",
937
+ "page:tabs",
938
+ "pagination",
939
+ "password",
940
+ "percent",
941
+ "phone",
942
+ "pie-chart",
943
+ "pivot",
944
+ "plugin-calendar:calendar-view",
945
+ "plugin-calendar:object-calendar",
946
+ "plugin-charts:advanced-chart",
947
+ "plugin-charts:area-chart",
948
+ "plugin-charts:bar-chart",
949
+ "plugin-charts:chart",
950
+ "plugin-charts:chart:bar",
951
+ "plugin-charts:donut-chart",
952
+ "plugin-charts:line-chart",
953
+ "plugin-charts:object-chart",
954
+ "plugin-charts:pie-chart",
955
+ "plugin-charts:radar-chart",
956
+ "plugin-charts:scatter-chart",
957
+ "plugin-chatbot:chatbot",
958
+ "plugin-chatbot:chatbot-enhanced",
959
+ "plugin-chatbot:chatbot-floating",
960
+ "plugin-dashboard:dashboard",
961
+ "plugin-dashboard:dashboard-grid",
962
+ "plugin-dashboard:metric",
963
+ "plugin-dashboard:metric-card",
964
+ "plugin-dashboard:object-data-table",
965
+ "plugin-dashboard:object-metric",
966
+ "plugin-dashboard:object-pivot",
967
+ "plugin-dashboard:pivot",
968
+ "plugin-designer:app-creation-wizard",
969
+ "plugin-designer:branding-editor",
970
+ "plugin-designer:dashboard-editor",
971
+ "plugin-designer:data-model-designer",
972
+ "plugin-designer:field-designer",
973
+ "plugin-designer:navigation-designer",
974
+ "plugin-designer:object-manager",
975
+ "plugin-designer:page-designer",
976
+ "plugin-designer:process-designer",
977
+ "plugin-designer:report-designer",
978
+ "plugin-detail:detail-section",
979
+ "plugin-detail:detail-view",
980
+ "plugin-detail:related-list",
981
+ "plugin-editor:code-editor",
982
+ "plugin-form:embeddable-form",
983
+ "plugin-form:form-analytics",
984
+ "plugin-form:object-form",
985
+ "plugin-form:object-master-detail-form",
986
+ "plugin-gantt:object-gantt",
987
+ "plugin-grid:import-wizard",
988
+ "plugin-grid:object-grid",
989
+ "plugin-kanban:kanban-enhanced",
990
+ "plugin-kanban:kanban-ui",
991
+ "plugin-kanban:object-kanban",
992
+ "plugin-list:list-view",
993
+ "plugin-list:object-gallery",
994
+ "plugin-map:object-map",
995
+ "plugin-markdown:markdown",
996
+ "plugin-report:report",
997
+ "plugin-report:report-viewer",
998
+ "plugin-report:spec-report",
999
+ "plugin-timeline:object-timeline",
1000
+ "plugin-timeline:timeline",
1001
+ "plugin-tree:object-tree",
1002
+ "plugin-view:object-view",
1003
+ "plugin-view:view",
1004
+ "plugin-view:view:simple",
1005
+ "popover",
1006
+ "pre",
1007
+ "process-designer",
1008
+ "progress",
1009
+ "protocol-placeholder:ai:feedback",
1010
+ "protocol-placeholder:ai:input",
1011
+ "protocol-placeholder:ai:suggestion",
1012
+ "protocol-placeholder:app:launcher",
1013
+ "protocol-placeholder:field:address",
1014
+ "protocol-placeholder:field:audio",
1015
+ "protocol-placeholder:field:avatar",
1016
+ "protocol-placeholder:field:boolean",
1017
+ "protocol-placeholder:field:checkboxes",
1018
+ "protocol-placeholder:field:code",
1019
+ "protocol-placeholder:field:color",
1020
+ "protocol-placeholder:field:currency",
1021
+ "protocol-placeholder:field:date",
1022
+ "protocol-placeholder:field:datetime",
1023
+ "protocol-placeholder:field:duration",
1024
+ "protocol-placeholder:field:email",
1025
+ "protocol-placeholder:field:file",
1026
+ "protocol-placeholder:field:html",
1027
+ "protocol-placeholder:field:image",
1028
+ "protocol-placeholder:field:json",
1029
+ "protocol-placeholder:field:location",
1030
+ "protocol-placeholder:field:lookup",
1031
+ "protocol-placeholder:field:markdown",
1032
+ "protocol-placeholder:field:master_detail",
1033
+ "protocol-placeholder:field:multiselect",
1034
+ "protocol-placeholder:field:number",
1035
+ "protocol-placeholder:field:password",
1036
+ "protocol-placeholder:field:percent",
1037
+ "protocol-placeholder:field:phone",
1038
+ "protocol-placeholder:field:progress",
1039
+ "protocol-placeholder:field:qrcode",
1040
+ "protocol-placeholder:field:radio",
1041
+ "protocol-placeholder:field:rating",
1042
+ "protocol-placeholder:field:select",
1043
+ "protocol-placeholder:field:signature",
1044
+ "protocol-placeholder:field:slider",
1045
+ "protocol-placeholder:field:text",
1046
+ "protocol-placeholder:field:textarea",
1047
+ "protocol-placeholder:field:time",
1048
+ "protocol-placeholder:field:tree",
1049
+ "protocol-placeholder:field:url",
1050
+ "protocol-placeholder:field:video",
1051
+ "protocol-placeholder:global:notifications",
1052
+ "protocol-placeholder:global:search",
1053
+ "protocol-placeholder:nav:breadcrumb",
1054
+ "protocol-placeholder:nav:menu",
1055
+ "protocol-placeholder:page-header",
1056
+ "protocol-placeholder:page:accordion",
1057
+ "protocol-placeholder:page:card",
1058
+ "protocol-placeholder:page:footer",
1059
+ "protocol-placeholder:page:header",
1060
+ "protocol-placeholder:page:sidebar",
1061
+ "protocol-placeholder:page:tabs",
1062
+ "protocol-placeholder:record:activity",
1063
+ "protocol-placeholder:record:chatter",
1064
+ "protocol-placeholder:record:details",
1065
+ "protocol-placeholder:record:highlights",
1066
+ "protocol-placeholder:record:path",
1067
+ "protocol-placeholder:record:related_list",
1068
+ "protocol-placeholder:user:profile",
1069
+ "protocol-placeholder:view:calendar",
1070
+ "protocol-placeholder:view:drawer",
1071
+ "protocol-placeholder:view:gallery",
1072
+ "protocol-placeholder:view:gantt",
1073
+ "protocol-placeholder:view:grid",
1074
+ "protocol-placeholder:view:kanban",
1075
+ "protocol-placeholder:view:map",
1076
+ "protocol-placeholder:view:modal",
1077
+ "protocol-placeholder:view:simple",
1078
+ "protocol-placeholder:view:split",
1079
+ "protocol-placeholder:view:tabbed",
1080
+ "protocol-placeholder:view:timeline",
1081
+ "protocol-placeholder:view:wizard",
1082
+ "protocol-placeholder:widget:bar",
1083
+ "protocol-placeholder:widget:funnel",
1084
+ "protocol-placeholder:widget:heatmap",
1085
+ "protocol-placeholder:widget:image",
1086
+ "protocol-placeholder:widget:line",
1087
+ "protocol-placeholder:widget:metric",
1088
+ "protocol-placeholder:widget:pie",
1089
+ "protocol-placeholder:widget:pivot",
1090
+ "protocol-placeholder:widget:radar",
1091
+ "protocol-placeholder:widget:scatter",
1092
+ "protocol-placeholder:widget:table",
1093
+ "protocol-placeholder:widget:text",
1094
+ "q",
1095
+ "qrcode",
1096
+ "radar-chart",
1097
+ "radio",
1098
+ "radio-group",
1099
+ "rating",
1100
+ "record",
1101
+ "record:activity",
1102
+ "record:alert",
1103
+ "record:approvals",
1104
+ "record:attachments",
1105
+ "record:chatter",
1106
+ "record:details",
1107
+ "record:discussion",
1108
+ "record:highlights",
1109
+ "record:history",
1110
+ "record:line_items",
1111
+ "record:path",
1112
+ "record:quick_actions",
1113
+ "record:reference_rail",
1114
+ "record:related_list",
1115
+ "related-list",
1116
+ "report",
1117
+ "report-designer",
1118
+ "report-viewer",
1119
+ "report:report",
1120
+ "report:report-viewer",
1121
+ "report:spec-report",
1122
+ "resizable",
1123
+ "responsive-grid",
1124
+ "richtext",
1125
+ "scatter-chart",
1126
+ "scroll-area",
1127
+ "section",
1128
+ "select",
1129
+ "separator",
1130
+ "shared-view-link",
1131
+ "sheet",
1132
+ "sidebar",
1133
+ "sidebar-content",
1134
+ "sidebar-footer",
1135
+ "sidebar-group",
1136
+ "sidebar-header",
1137
+ "sidebar-inset",
1138
+ "sidebar-menu",
1139
+ "sidebar-menu-button",
1140
+ "sidebar-menu-item",
1141
+ "sidebar-provider",
1142
+ "sidebar-trigger",
1143
+ "signature",
1144
+ "skeleton",
1145
+ "slider",
1146
+ "small",
1147
+ "sonner",
1148
+ "sort-ui",
1149
+ "span",
1150
+ "spec-report",
1151
+ "spinner",
1152
+ "stack",
1153
+ "statistic",
1154
+ "strong",
1155
+ "sub",
1156
+ "summary",
1157
+ "sup",
1158
+ "switch",
1159
+ "table",
1160
+ "tabs",
1161
+ "tags",
1162
+ "text",
1163
+ "textarea",
1164
+ "time",
1165
+ "timeline",
1166
+ "toast",
1167
+ "toaster",
1168
+ "toggle",
1169
+ "toggle-group",
1170
+ "tooltip",
1171
+ "tree",
1172
+ "tree-view",
1173
+ "u",
1174
+ "ui:a",
1175
+ "ui:abbr",
1176
+ "ui:accordion",
1177
+ "ui:address",
1178
+ "ui:alert",
1179
+ "ui:alert-dialog",
1180
+ "ui:article",
1181
+ "ui:aside",
1182
+ "ui:aspect-ratio",
1183
+ "ui:avatar",
1184
+ "ui:b",
1185
+ "ui:badge",
1186
+ "ui:blockquote",
1187
+ "ui:br",
1188
+ "ui:breadcrumb",
1189
+ "ui:button",
1190
+ "ui:button-group",
1191
+ "ui:calendar",
1192
+ "ui:card",
1193
+ "ui:carousel",
1194
+ "ui:checkbox",
1195
+ "ui:cite",
1196
+ "ui:collapsible",
1197
+ "ui:combobox",
1198
+ "ui:command",
1199
+ "ui:container",
1200
+ "ui:context-menu",
1201
+ "ui:data-table",
1202
+ "ui:date-picker",
1203
+ "ui:dd",
1204
+ "ui:del",
1205
+ "ui:dialog",
1206
+ "ui:div",
1207
+ "ui:dl",
1208
+ "ui:drawer",
1209
+ "ui:dropdown-menu",
1210
+ "ui:dt",
1211
+ "ui:em",
1212
+ "ui:email",
1213
+ "ui:empty",
1214
+ "ui:figcaption",
1215
+ "ui:figure",
1216
+ "ui:file-upload",
1217
+ "ui:filter-builder",
1218
+ "ui:flex",
1219
+ "ui:footer",
1220
+ "ui:grid",
1221
+ "ui:h1",
1222
+ "ui:h2",
1223
+ "ui:h3",
1224
+ "ui:h4",
1225
+ "ui:h5",
1226
+ "ui:h6",
1227
+ "ui:header",
1228
+ "ui:header-bar",
1229
+ "ui:hover-card",
1230
+ "ui:hr",
1231
+ "ui:html",
1232
+ "ui:i",
1233
+ "ui:icon",
1234
+ "ui:image",
1235
+ "ui:img",
1236
+ "ui:input",
1237
+ "ui:input-otp",
1238
+ "ui:ins",
1239
+ "ui:kbd",
1240
+ "ui:label",
1241
+ "ui:li",
1242
+ "ui:list",
1243
+ "ui:loading",
1244
+ "ui:main",
1245
+ "ui:mark",
1246
+ "ui:menubar",
1247
+ "ui:nav",
1248
+ "ui:navigation-menu",
1249
+ "ui:ol",
1250
+ "ui:p",
1251
+ "ui:pagination",
1252
+ "ui:password",
1253
+ "ui:popover",
1254
+ "ui:pre",
1255
+ "ui:progress",
1256
+ "ui:q",
1257
+ "ui:radio-group",
1258
+ "ui:resizable",
1259
+ "ui:scroll-area",
1260
+ "ui:section",
1261
+ "ui:select",
1262
+ "ui:separator",
1263
+ "ui:sheet",
1264
+ "ui:sidebar",
1265
+ "ui:sidebar-content",
1266
+ "ui:sidebar-footer",
1267
+ "ui:sidebar-group",
1268
+ "ui:sidebar-header",
1269
+ "ui:sidebar-inset",
1270
+ "ui:sidebar-menu",
1271
+ "ui:sidebar-menu-button",
1272
+ "ui:sidebar-menu-item",
1273
+ "ui:sidebar-provider",
1274
+ "ui:sidebar-trigger",
1275
+ "ui:skeleton",
1276
+ "ui:slider",
1277
+ "ui:small",
1278
+ "ui:sonner",
1279
+ "ui:span",
1280
+ "ui:spinner",
1281
+ "ui:stack",
1282
+ "ui:statistic",
1283
+ "ui:strong",
1284
+ "ui:sub",
1285
+ "ui:sup",
1286
+ "ui:switch",
1287
+ "ui:table",
1288
+ "ui:tabs",
1289
+ "ui:text",
1290
+ "ui:textarea",
1291
+ "ui:time",
1292
+ "ui:toast",
1293
+ "ui:toaster",
1294
+ "ui:toggle",
1295
+ "ui:toggle-group",
1296
+ "ui:tooltip",
1297
+ "ui:tree-view",
1298
+ "ui:u",
1299
+ "ui:ul",
1300
+ "ul",
1301
+ "url",
1302
+ "user",
1303
+ "user:profile",
1304
+ "utility",
1305
+ "vector",
1306
+ "view",
1307
+ "view-switcher",
1308
+ "view:calendar",
1309
+ "view:chart",
1310
+ "view:dashboard",
1311
+ "view:detail",
1312
+ "view:drawer",
1313
+ "view:filter-ui",
1314
+ "view:form",
1315
+ "view:gallery",
1316
+ "view:gantt",
1317
+ "view:grid",
1318
+ "view:kanban",
1319
+ "view:list",
1320
+ "view:map",
1321
+ "view:modal",
1322
+ "view:shared-view-link",
1323
+ "view:simple",
1324
+ "view:sort-ui",
1325
+ "view:split",
1326
+ "view:tabbed",
1327
+ "view:timeline",
1328
+ "view:tree",
1329
+ "view:view-switcher",
1330
+ "view:wizard",
1331
+ "widget:bar",
1332
+ "widget:funnel",
1333
+ "widget:heatmap",
1334
+ "widget:image",
1335
+ "widget:line",
1336
+ "widget:metric",
1337
+ "widget:pie",
1338
+ "widget:pivot",
1339
+ "widget:radar",
1340
+ "widget:scatter",
1341
+ "widget:table",
1342
+ "widget:text"
1343
+ ];
1344
+ var KNOWN_SCHEMA_TYPE_SET = new Set(KNOWN_SCHEMA_TYPES);
1345
+ function isKnownSchemaType(type) {
1346
+ return KNOWN_SCHEMA_TYPE_SET.has(type);
1347
+ }
1348
+
1349
+ // src/commands/check.ts
1350
+ var OBJECTUI_STRUCTURAL_KEYS = [
1351
+ // Composition — the `children`/`body`-class keys the ruling names.
1352
+ "body",
1353
+ "children",
1354
+ // Presentation.
1355
+ "className",
1356
+ "style",
1357
+ "placeholder",
1358
+ // Conditional rendering and interaction state.
1359
+ "visible",
1360
+ "visibleWhen",
1361
+ "visibleOn",
1362
+ "hidden",
1363
+ "hiddenOn",
1364
+ "disabled",
1365
+ "disabledOn",
1366
+ // Test and accessibility handles.
1367
+ "testId",
1368
+ "ariaLabel"
1369
+ ];
1370
+ function isObjectUiSchemaFile(content) {
1371
+ return OBJECTUI_STRUCTURAL_KEYS.some((key) => key in content);
1372
+ }
1373
+ function describeParseError(text, error) {
1374
+ const upTo = text.slice(0, error.offset);
1375
+ const line = upTo.split("\n").length;
1376
+ const column = error.offset - (upTo.lastIndexOf("\n") + 1) + 1;
1377
+ return `${printParseErrorCode(error.error)} at line ${line} column ${column}`;
1378
+ }
1379
+ async function check(cwd = process.cwd()) {
668
1380
  console.log(chalk10.bold("Object UI Schema Check"));
669
- const cwd = process.cwd();
670
1381
  const files = globSync("**/*.{json,yaml,yml}", {
671
1382
  cwd,
672
1383
  ignore: ["node_modules/**", "dist/**", ".git/**"]
673
1384
  });
674
1385
  console.log(`Analyzing ${files.length} files...`);
675
1386
  let errors = 0;
1387
+ let skipped = 0;
676
1388
  for (const file of files) {
677
1389
  try {
678
1390
  if (file.endsWith(".json")) {
679
- const content = JSON.parse(readFileSync2(join9(cwd, file), "utf-8"));
1391
+ const text = readFileSync2(join9(cwd, file), "utf-8");
1392
+ const parseErrors = [];
1393
+ const content = parseJsonc(text, parseErrors, { allowTrailingComma: true });
1394
+ if (parseErrors.length > 0) {
1395
+ const [first] = parseErrors;
1396
+ console.log(
1397
+ chalk10.red(`x Invalid JSON in ${file}: ${describeParseError(text, first)}`)
1398
+ );
1399
+ errors++;
1400
+ continue;
1401
+ }
680
1402
  if (content && typeof content === "object" && content.type) {
681
- const knownTypes = [
682
- "page",
683
- "form",
684
- "grid",
685
- "crud",
686
- "kanban",
687
- "calendar",
688
- "dashboard",
689
- "chart",
690
- "detail",
691
- "list",
692
- "timeline",
693
- "gantt",
694
- "map",
695
- "gallery",
696
- "object-view",
697
- "detail-view",
698
- "object-chart"
699
- ];
700
- if (typeof content.type === "string" && !knownTypes.includes(content.type)) {
701
- console.log(chalk10.yellow(`\u26A0\uFE0F Unknown schema type "${content.type}" in ${file}`));
1403
+ if (typeof content.type === "string") {
1404
+ if (!isObjectUiSchemaFile(content)) {
1405
+ skipped++;
1406
+ } else if (!isKnownSchemaType(content.type)) {
1407
+ console.log(chalk10.yellow(`\u26A0\uFE0F Unknown schema type "${content.type}" in ${file}`));
1408
+ }
702
1409
  }
703
1410
  }
704
1411
  }
@@ -707,6 +1414,18 @@ async function check() {
707
1414
  errors++;
708
1415
  }
709
1416
  }
1417
+ if (skipped > 0) {
1418
+ console.log(
1419
+ chalk10.dim(
1420
+ `Skipped ${skipped} file${skipped === 1 ? "" : "s"} with a root "type" and no ObjectUI schema marker.`
1421
+ )
1422
+ );
1423
+ console.log(
1424
+ chalk10.dim(
1425
+ ` A file is checked when its root carries an ObjectUI structural key: ${OBJECTUI_STRUCTURAL_KEYS.join(", ")}.`
1426
+ )
1427
+ );
1428
+ }
710
1429
  if (errors === 0) {
711
1430
  console.log(chalk10.green("\u2713 All checks passed"));
712
1431
  } else {
@@ -717,8 +1436,8 @@ async function check() {
717
1436
 
718
1437
  // src/commands/validate.ts
719
1438
  import chalk11 from "chalk";
720
- import { readFileSync as readFileSync3, existsSync as existsSync9 } from "fs";
721
- import { resolve as resolve5 } from "path";
1439
+ import { readFileSync as readFileSync3, existsSync as existsSync8 } from "fs";
1440
+ import { resolve as resolve4 } from "path";
722
1441
  import { load as loadYaml } from "js-yaml";
723
1442
  import { safeValidateSchema } from "@object-ui/types/zod";
724
1443
 
@@ -754,8 +1473,8 @@ function findSpecVocabularyFormFields(node, path = "") {
754
1473
  // src/commands/validate.ts
755
1474
  async function validate(schemaPath) {
756
1475
  console.log(chalk11.blue("\u{1F50D} ObjectUI Schema Validator\n"));
757
- const resolvedPath = resolve5(process.cwd(), schemaPath);
758
- if (!existsSync9(resolvedPath)) {
1476
+ const resolvedPath = resolve4(process.cwd(), schemaPath);
1477
+ if (!existsSync8(resolvedPath)) {
759
1478
  console.error(chalk11.red(`\u2717 Error: Schema file not found: ${schemaPath}`));
760
1479
  process.exit(1);
761
1480
  }
@@ -846,17 +1565,17 @@ ${index + 1}. ${issue.message}`));
846
1565
  // src/commands/create-plugin.ts
847
1566
  import chalk12 from "chalk";
848
1567
  import { spawn as spawn2 } from "child_process";
849
- import { resolve as resolve6, dirname as dirname3 } from "path";
1568
+ import { resolve as resolve5, dirname as dirname3 } from "path";
850
1569
  import { fileURLToPath as fileURLToPath2 } from "url";
851
1570
  var __filename = fileURLToPath2(import.meta.url);
852
1571
  var __dirname = dirname3(__filename);
853
1572
  async function createPlugin(pluginName) {
854
1573
  console.log(chalk12.blue("\u{1F680} Creating ObjectUI plugin...\n"));
855
- const createPluginScript = resolve6(
1574
+ const createPluginScript = resolve5(
856
1575
  __dirname,
857
1576
  "../../../create-plugin/dist/index.js"
858
1577
  );
859
- return new Promise((resolve8, reject) => {
1578
+ return new Promise((resolve7, reject) => {
860
1579
  const child = spawn2("node", [createPluginScript, pluginName], {
861
1580
  stdio: "inherit",
862
1581
  shell: true
@@ -867,7 +1586,7 @@ async function createPlugin(pluginName) {
867
1586
  });
868
1587
  child.on("exit", (code) => {
869
1588
  if (code === 0) {
870
- resolve8();
1589
+ resolve7();
871
1590
  } else {
872
1591
  reject(new Error(`create-plugin exited with code ${code}`));
873
1592
  }
@@ -877,12 +1596,12 @@ async function createPlugin(pluginName) {
877
1596
 
878
1597
  // src/commands/analyze.ts
879
1598
  import chalk13 from "chalk";
880
- import { existsSync as existsSync10, statSync as statSync2, readdirSync } from "fs";
881
- import { resolve as resolve7, join as join10, extname } from "path";
1599
+ import { existsSync as existsSync9, statSync, readdirSync } from "fs";
1600
+ import { resolve as resolve6, join as join10, extname } from "path";
882
1601
  async function analyzeBundleSize() {
883
1602
  console.log(chalk13.bold("\n\u{1F4E6} Bundle Size Analysis\n"));
884
- const distDir = resolve7(process.cwd(), "dist");
885
- if (!existsSync10(distDir)) {
1603
+ const distDir = resolve6(process.cwd(), "dist");
1604
+ if (!existsSync9(distDir)) {
886
1605
  console.log(chalk13.yellow("\u26A0 No dist directory found. Run build first."));
887
1606
  return;
888
1607
  }
@@ -891,7 +1610,7 @@ async function analyzeBundleSize() {
891
1610
  const items = readdirSync(dir);
892
1611
  for (const item of items) {
893
1612
  const fullPath = join10(dir, item);
894
- const stat = statSync2(fullPath);
1613
+ const stat = statSync(fullPath);
895
1614
  if (stat.isDirectory()) {
896
1615
  scanDirectory(fullPath);
897
1616
  } else {
@@ -981,7 +1700,7 @@ var packageJson = JSON.parse(
981
1700
  );
982
1701
  var program = new Command();
983
1702
  program.name("objectui").description("CLI tool for Object UI - Build applications from JSON schemas").version(packageJson.version);
984
- 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) => {
1703
+ program.command("serve").description("Start a development server with your JSON/YAML schema").argument("[schema]", "Path to JSON/YAML schema file, or a project / pages directory", "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) => {
985
1704
  try {
986
1705
  await serve(schema, options);
987
1706
  } catch (error) {
@@ -989,7 +1708,7 @@ program.command("serve").description("Start a development server with your JSON/
989
1708
  process.exit(1);
990
1709
  }
991
1710
  });
992
- 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) => {
1711
+ program.command("dev").description("Start development server (alias for serve)").argument("[schema]", "Path to JSON/YAML schema file, or a project / pages directory", "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) => {
993
1712
  try {
994
1713
  await dev(schema, options);
995
1714
  } catch (error) {
@@ -997,7 +1716,7 @@ program.command("dev").description("Start development server (alias for serve)")
997
1716
  process.exit(1);
998
1717
  }
999
1718
  });
1000
- 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) => {
1719
+ program.command("build").description("Build application for production").argument("[schema]", "Path to JSON/YAML schema file, or a project / pages directory", "app.json").option("-o, --out-dir <dir>", "Output directory", "dist").option("--clean", "Clean output directory before build", false).action(async (schema, options) => {
1001
1720
  try {
1002
1721
  await buildApp(schema, options);
1003
1722
  } catch (error) {