@object-ui/cli 17.6.0 → 18.0.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/CHANGELOG.md +2505 -0
- package/README.md +14 -24
- package/dist/{chunk-AP2INOE7.js → chunk-VMMIGYU3.js} +79 -80
- package/dist/chunk-VMMIGYU3.js.map +1 -0
- package/dist/cli.js +621 -507
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +7 -6
- package/dist/chunk-AP2INOE7.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
reportProjectSource,
|
|
9
9
|
resolveProjectSource,
|
|
10
10
|
serve
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-VMMIGYU3.js";
|
|
12
12
|
|
|
13
13
|
// src/cli.ts
|
|
14
14
|
import { Command } from "commander";
|
|
15
|
-
import
|
|
15
|
+
import chalk9 from "chalk";
|
|
16
16
|
|
|
17
17
|
// src/commands/dev.ts
|
|
18
18
|
import { createServer } from "vite";
|
|
@@ -212,108 +212,10 @@ Make sure you have a valid production build.`
|
|
|
212
212
|
});
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
// src/commands/lint.ts
|
|
216
|
-
import { execSync as execSync3 } from "child_process";
|
|
217
|
-
import { existsSync as existsSync3 } from "fs";
|
|
218
|
-
import { join as join4 } from "path";
|
|
219
|
-
import chalk4 from "chalk";
|
|
220
|
-
async function lint(options) {
|
|
221
|
-
const cwd = process.cwd();
|
|
222
|
-
console.log(chalk4.blue("\u{1F50D} Running linter...\n"));
|
|
223
|
-
const tmpDir = join4(cwd, ".objectui-tmp");
|
|
224
|
-
const hasTempApp = existsSync3(tmpDir);
|
|
225
|
-
if (!hasTempApp) {
|
|
226
|
-
throw new Error(
|
|
227
|
-
"No Object UI application found. Run 'objectui dev' first to generate the application."
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
const packageJsonPath = join4(tmpDir, "package.json");
|
|
231
|
-
const nodeModulesPath = join4(tmpDir, "node_modules");
|
|
232
|
-
if (!existsSync3(packageJsonPath) || !existsSync3(nodeModulesPath)) {
|
|
233
|
-
throw new Error(
|
|
234
|
-
"Dependencies not installed. Run 'objectui dev' first to set up the application."
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
try {
|
|
238
|
-
const fixFlag = options.fix ? "--fix" : "";
|
|
239
|
-
const command = `npx eslint "src/**/*.{js,jsx,ts,tsx}" ${fixFlag}`.trim();
|
|
240
|
-
console.log(chalk4.dim(` Running: ${command}
|
|
241
|
-
`));
|
|
242
|
-
execSync3(command, {
|
|
243
|
-
cwd: tmpDir,
|
|
244
|
-
stdio: "inherit"
|
|
245
|
-
});
|
|
246
|
-
console.log();
|
|
247
|
-
console.log(chalk4.green("\u2713 Linting completed successfully!"));
|
|
248
|
-
console.log();
|
|
249
|
-
} catch {
|
|
250
|
-
console.log();
|
|
251
|
-
console.log(chalk4.yellow("\u26A0 Linting found issues."));
|
|
252
|
-
if (!options.fix) {
|
|
253
|
-
console.log(chalk4.dim(" Run 'objectui lint --fix' to automatically fix some issues."));
|
|
254
|
-
}
|
|
255
|
-
console.log();
|
|
256
|
-
process.exit(1);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// src/commands/test.ts
|
|
261
|
-
import { execSync as execSync4 } from "child_process";
|
|
262
|
-
import { existsSync as existsSync4 } from "fs";
|
|
263
|
-
import { join as join5 } from "path";
|
|
264
|
-
import chalk5 from "chalk";
|
|
265
|
-
async function test(options) {
|
|
266
|
-
const cwd = process.cwd();
|
|
267
|
-
console.log(chalk5.blue("\u{1F9EA} Running tests...\n"));
|
|
268
|
-
const tmpDir = join5(cwd, ".objectui-tmp");
|
|
269
|
-
const hasTempApp = existsSync4(tmpDir);
|
|
270
|
-
if (!hasTempApp) {
|
|
271
|
-
throw new Error(
|
|
272
|
-
"No Object UI application found. Run 'objectui dev' first to generate the application."
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
const packageJsonPath = join5(tmpDir, "package.json");
|
|
276
|
-
const nodeModulesPath = join5(tmpDir, "node_modules");
|
|
277
|
-
if (!existsSync4(packageJsonPath) || !existsSync4(nodeModulesPath)) {
|
|
278
|
-
throw new Error(
|
|
279
|
-
"Dependencies not installed. Run 'objectui dev' first to set up the application."
|
|
280
|
-
);
|
|
281
|
-
}
|
|
282
|
-
try {
|
|
283
|
-
let command = "npx vitest";
|
|
284
|
-
if (options.watch) {
|
|
285
|
-
command += " --watch";
|
|
286
|
-
} else if (options.ui) {
|
|
287
|
-
command += " --ui";
|
|
288
|
-
} else {
|
|
289
|
-
command += " run";
|
|
290
|
-
}
|
|
291
|
-
if (options.coverage) {
|
|
292
|
-
command += " --coverage";
|
|
293
|
-
}
|
|
294
|
-
console.log(chalk5.dim(` Running: ${command}
|
|
295
|
-
`));
|
|
296
|
-
execSync4(command, {
|
|
297
|
-
cwd: tmpDir,
|
|
298
|
-
stdio: "inherit"
|
|
299
|
-
});
|
|
300
|
-
if (!options.watch && !options.ui) {
|
|
301
|
-
console.log();
|
|
302
|
-
console.log(chalk5.green("\u2713 Tests completed successfully!"));
|
|
303
|
-
console.log();
|
|
304
|
-
}
|
|
305
|
-
} catch {
|
|
306
|
-
console.log();
|
|
307
|
-
console.log(chalk5.red("\u2717 Some tests failed."));
|
|
308
|
-
console.log();
|
|
309
|
-
process.exit(1);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
215
|
// src/commands/generate.ts
|
|
314
|
-
import
|
|
315
|
-
import { existsSync as
|
|
316
|
-
import { join as
|
|
216
|
+
import chalk4 from "chalk";
|
|
217
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, writeFileSync } from "fs";
|
|
218
|
+
import { join as join4 } from "path";
|
|
317
219
|
async function generate(type, name) {
|
|
318
220
|
const cwd = process.cwd();
|
|
319
221
|
switch (type) {
|
|
@@ -328,18 +230,18 @@ async function generate(type, name) {
|
|
|
328
230
|
generatePlugin(cwd, name);
|
|
329
231
|
break;
|
|
330
232
|
default:
|
|
331
|
-
console.log(
|
|
233
|
+
console.log(chalk4.red(`Unknown type: ${type}`));
|
|
332
234
|
console.log(`Available types: resource, page, plugin`);
|
|
333
235
|
process.exit(1);
|
|
334
236
|
}
|
|
335
237
|
}
|
|
336
238
|
function generateResource(cwd, name) {
|
|
337
|
-
const dir =
|
|
338
|
-
if (!
|
|
239
|
+
const dir = join4(cwd, "objects");
|
|
240
|
+
if (!existsSync3(dir)) mkdirSync3(dir, { recursive: true });
|
|
339
241
|
const fileName = `${name.toLowerCase()}.json`;
|
|
340
|
-
const filePath =
|
|
341
|
-
if (
|
|
342
|
-
console.log(
|
|
242
|
+
const filePath = join4(dir, fileName);
|
|
243
|
+
if (existsSync3(filePath)) {
|
|
244
|
+
console.log(chalk4.yellow(`Object ${name} already exists at ${filePath}`));
|
|
343
245
|
return;
|
|
344
246
|
}
|
|
345
247
|
const content = {
|
|
@@ -349,34 +251,35 @@ function generateResource(cwd, name) {
|
|
|
349
251
|
}
|
|
350
252
|
};
|
|
351
253
|
writeFileSync(filePath, JSON.stringify(content, null, 2));
|
|
352
|
-
console.log(
|
|
254
|
+
console.log(chalk4.green(`\u2713 Generated resource schema: ${filePath}`));
|
|
353
255
|
}
|
|
354
256
|
function generatePage(cwd, name) {
|
|
355
|
-
const dir =
|
|
356
|
-
if (!
|
|
257
|
+
const dir = join4(cwd, "pages");
|
|
258
|
+
if (!existsSync3(dir)) mkdirSync3(dir, { recursive: true });
|
|
357
259
|
const fileName = `${name.toLowerCase()}.json`;
|
|
358
|
-
const filePath =
|
|
359
|
-
if (
|
|
360
|
-
console.log(
|
|
260
|
+
const filePath = join4(dir, fileName);
|
|
261
|
+
if (existsSync3(filePath)) {
|
|
262
|
+
console.log(chalk4.yellow(`Page ${name} already exists at ${filePath}`));
|
|
361
263
|
return;
|
|
362
264
|
}
|
|
363
265
|
const content = {
|
|
364
266
|
type: "page",
|
|
267
|
+
pageType: "app",
|
|
365
268
|
title: name,
|
|
366
|
-
|
|
269
|
+
children: [
|
|
367
270
|
{
|
|
368
271
|
type: "markdown",
|
|
369
|
-
content:
|
|
272
|
+
content: `Welcome to ${name}`
|
|
370
273
|
}
|
|
371
274
|
]
|
|
372
275
|
};
|
|
373
276
|
writeFileSync(filePath, JSON.stringify(content, null, 2));
|
|
374
|
-
console.log(
|
|
277
|
+
console.log(chalk4.green(`\u2713 Generated page schema: ${filePath}`));
|
|
375
278
|
}
|
|
376
279
|
function generatePlugin(cwd, name) {
|
|
377
|
-
const dir =
|
|
378
|
-
if (
|
|
379
|
-
console.log(
|
|
280
|
+
const dir = join4(cwd, "plugins", name);
|
|
281
|
+
if (existsSync3(dir)) {
|
|
282
|
+
console.log(chalk4.yellow(`Plugin ${name} already exists`));
|
|
380
283
|
return;
|
|
381
284
|
}
|
|
382
285
|
mkdirSync3(dir, { recursive: true });
|
|
@@ -388,14 +291,14 @@ export const ${name}Plugin = {
|
|
|
388
291
|
}
|
|
389
292
|
};
|
|
390
293
|
`;
|
|
391
|
-
writeFileSync(
|
|
392
|
-
console.log(
|
|
294
|
+
writeFileSync(join4(dir, "index.ts"), content.trim());
|
|
295
|
+
console.log(chalk4.green(`\u2713 Generated plugin: ${dir}`));
|
|
393
296
|
}
|
|
394
297
|
|
|
395
298
|
// src/commands/doctor.ts
|
|
396
|
-
import
|
|
397
|
-
import { existsSync as
|
|
398
|
-
import { dirname, join as
|
|
299
|
+
import chalk5 from "chalk";
|
|
300
|
+
import { existsSync as existsSync4, readFileSync } from "fs";
|
|
301
|
+
import { dirname, join as join5, resolve as resolvePath } from "path";
|
|
399
302
|
var CSS_ENTRY_CANDIDATES = [
|
|
400
303
|
"src/index.css",
|
|
401
304
|
"src/main.css",
|
|
@@ -430,15 +333,15 @@ var V4_POSTCSS_PLUGIN = /@tailwindcss\/postcss/;
|
|
|
430
333
|
var V3_POSTCSS_PLUGIN = /["']tailwindcss["']|(?:^|[{,\s])tailwindcss\s*:/m;
|
|
431
334
|
function readIfExists(path) {
|
|
432
335
|
try {
|
|
433
|
-
return
|
|
336
|
+
return existsSync4(path) ? readFileSync(path, "utf-8") : null;
|
|
434
337
|
} catch {
|
|
435
338
|
return null;
|
|
436
339
|
}
|
|
437
340
|
}
|
|
438
341
|
function findFile(cwd, candidates) {
|
|
439
342
|
for (const rel of candidates) {
|
|
440
|
-
const abs =
|
|
441
|
-
if (
|
|
343
|
+
const abs = join5(cwd, rel);
|
|
344
|
+
if (existsSync4(abs)) return abs;
|
|
442
345
|
}
|
|
443
346
|
return null;
|
|
444
347
|
}
|
|
@@ -451,7 +354,7 @@ function majorOf(range) {
|
|
|
451
354
|
function isInstalledFrom(cwd, specifier) {
|
|
452
355
|
let dir = resolvePath(cwd);
|
|
453
356
|
for (; ; ) {
|
|
454
|
-
if (
|
|
357
|
+
if (existsSync4(join5(dir, "node_modules", ...specifier.split("/")))) return true;
|
|
455
358
|
const parent = dirname(dir);
|
|
456
359
|
if (parent === dir) return false;
|
|
457
360
|
dir = parent;
|
|
@@ -468,7 +371,7 @@ function runDiagnostics(cwd) {
|
|
|
468
371
|
const error = (id, message) => {
|
|
469
372
|
results.push({ id, level: "error", message });
|
|
470
373
|
};
|
|
471
|
-
const pkgPath =
|
|
374
|
+
const pkgPath = join5(cwd, "package.json");
|
|
472
375
|
const pkgRaw = readIfExists(pkgPath);
|
|
473
376
|
let pkg = null;
|
|
474
377
|
if (pkgRaw === null) {
|
|
@@ -536,7 +439,7 @@ function runDiagnostics(cwd) {
|
|
|
536
439
|
}
|
|
537
440
|
const cssEntries = CSS_ENTRY_CANDIDATES.map((rel) => ({
|
|
538
441
|
rel,
|
|
539
|
-
content: readIfExists(
|
|
442
|
+
content: readIfExists(join5(cwd, rel))
|
|
540
443
|
})).filter((entry) => entry.content !== null);
|
|
541
444
|
const importsTailwind = cssEntries.some((entry) => V4_CSS_IMPORT.test(entry.content));
|
|
542
445
|
const usesV3Directives = cssEntries.some((entry) => V3_CSS_DIRECTIVE.test(entry.content));
|
|
@@ -570,7 +473,7 @@ function runDiagnostics(cwd) {
|
|
|
570
473
|
ok("tailwind-config-active", "JS Tailwind config is loaded via `@config`");
|
|
571
474
|
}
|
|
572
475
|
}
|
|
573
|
-
if (
|
|
476
|
+
if (existsSync4(join5(cwd, "tsconfig.json"))) {
|
|
574
477
|
ok("tsconfig-found", "tsconfig.json found");
|
|
575
478
|
const tsRange = deps.typescript;
|
|
576
479
|
if (tsRange) {
|
|
@@ -598,86 +501,224 @@ function countIssues(results) {
|
|
|
598
501
|
return results.filter((result) => result.level !== "ok").length;
|
|
599
502
|
}
|
|
600
503
|
async function doctor() {
|
|
601
|
-
console.log(
|
|
504
|
+
console.log(chalk5.bold("Object UI Doctor"));
|
|
602
505
|
console.log("Diagnosis in progress...\n");
|
|
603
506
|
const results = runDiagnostics(process.cwd());
|
|
604
507
|
for (const result of results) {
|
|
605
508
|
if (result.level === "ok") {
|
|
606
|
-
console.log(
|
|
509
|
+
console.log(chalk5.green(`\u2713 ${result.message}`));
|
|
607
510
|
} else if (result.level === "warn") {
|
|
608
|
-
console.log(
|
|
511
|
+
console.log(chalk5.yellow(`\u26A0\uFE0F ${result.message}`));
|
|
609
512
|
} else {
|
|
610
|
-
console.log(
|
|
513
|
+
console.log(chalk5.red(`x ${result.message}`));
|
|
611
514
|
}
|
|
612
515
|
}
|
|
613
516
|
const issues = countIssues(results);
|
|
614
517
|
console.log("\nResult:");
|
|
615
518
|
if (issues === 0) {
|
|
616
|
-
console.log(
|
|
519
|
+
console.log(chalk5.green("Everything looks good! \u2728"));
|
|
617
520
|
} else {
|
|
618
|
-
console.log(
|
|
521
|
+
console.log(chalk5.yellow(`Found ${issues} issue(s).`));
|
|
619
522
|
}
|
|
620
523
|
}
|
|
621
524
|
|
|
622
|
-
// src/commands/
|
|
623
|
-
import
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
525
|
+
// src/commands/check.ts
|
|
526
|
+
import chalk6 from "chalk";
|
|
527
|
+
import { globSync } from "glob";
|
|
528
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
529
|
+
import { join as join6 } from "path";
|
|
530
|
+
import { parse as parseJsonc, printParseErrorCode } from "jsonc-parser";
|
|
531
|
+
|
|
532
|
+
// src/utils/authoring-face.ts
|
|
533
|
+
import { StrictAnyComponentSchema } from "@object-ui/types/zod";
|
|
534
|
+
|
|
535
|
+
// src/utils/issue-path.ts
|
|
536
|
+
function formatIssuePath(path) {
|
|
537
|
+
const segments = path ?? [];
|
|
538
|
+
return segments.length > 0 ? segments.join(" \u2192 ") : "(root)";
|
|
628
539
|
}
|
|
629
540
|
|
|
630
|
-
// src/
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
];
|
|
646
|
-
let consolePath = null;
|
|
647
|
-
for (const candidate of candidates) {
|
|
648
|
-
if (existsSync7(join8(candidate, "package.json"))) {
|
|
649
|
-
consolePath = candidate;
|
|
650
|
-
break;
|
|
541
|
+
// src/utils/union-arm-diagnostics.ts
|
|
542
|
+
var MAX_UNION_ARMS_REPORTED = 5;
|
|
543
|
+
function editDistance(a, b) {
|
|
544
|
+
if (a === b) return 0;
|
|
545
|
+
if (a.length === 0) return b.length;
|
|
546
|
+
if (b.length === 0) return a.length;
|
|
547
|
+
let previous = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
548
|
+
for (let i = 1; i <= a.length; i += 1) {
|
|
549
|
+
const current = [i];
|
|
550
|
+
for (let j = 1; j <= b.length; j += 1) {
|
|
551
|
+
current[j] = Math.min(
|
|
552
|
+
previous[j] + 1,
|
|
553
|
+
current[j - 1] + 1,
|
|
554
|
+
previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1)
|
|
555
|
+
);
|
|
651
556
|
}
|
|
557
|
+
previous = current;
|
|
652
558
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
559
|
+
return previous[b.length];
|
|
560
|
+
}
|
|
561
|
+
function nearestArmNames(authoredType, armNames) {
|
|
562
|
+
const unique = [...new Set(armNames)].sort();
|
|
563
|
+
if (typeof authoredType !== "string" || authoredType === "") {
|
|
564
|
+
return { candidates: [], total: unique.length };
|
|
565
|
+
}
|
|
566
|
+
const ordered = [...unique].sort((x, y) => {
|
|
567
|
+
const d = editDistance(authoredType, x) - editDistance(authoredType, y);
|
|
568
|
+
return d !== 0 ? d : x.localeCompare(y);
|
|
569
|
+
});
|
|
570
|
+
return { candidates: ordered.slice(0, MAX_UNION_ARMS_REPORTED), total: unique.length };
|
|
571
|
+
}
|
|
572
|
+
function authoredTypeAt(document, path) {
|
|
573
|
+
let node = document;
|
|
574
|
+
for (const key of path) {
|
|
575
|
+
if (node === null || typeof node !== "object") return void 0;
|
|
576
|
+
node = node[key];
|
|
577
|
+
}
|
|
578
|
+
if (node === null || typeof node !== "object") return void 0;
|
|
579
|
+
const type = node.type;
|
|
580
|
+
return typeof type === "string" ? type : void 0;
|
|
581
|
+
}
|
|
582
|
+
function isUnion(issue) {
|
|
583
|
+
return issue.code === "invalid_union" && Array.isArray(issue.errors);
|
|
584
|
+
}
|
|
585
|
+
var NO_MATCHING_DISCRIMINATOR = "No matching discriminator";
|
|
586
|
+
function noArmAccepts(node, literals, document) {
|
|
587
|
+
const authoredType = authoredTypeAt(document, node);
|
|
588
|
+
const { candidates, total } = nearestArmNames(authoredType, literals);
|
|
589
|
+
return {
|
|
590
|
+
kind: "note",
|
|
591
|
+
path: [...node],
|
|
592
|
+
...authoredType === void 0 ? {} : { authoredType },
|
|
593
|
+
candidates,
|
|
594
|
+
totalArmNames: total
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
function noMatchingDiscriminator(issue, document) {
|
|
598
|
+
if (issue.code !== "invalid_union") return void 0;
|
|
599
|
+
if (issue.note !== NO_MATCHING_DISCRIMINATOR) return void 0;
|
|
600
|
+
if (!Array.isArray(issue.options)) return void 0;
|
|
601
|
+
if ((issue.errors ?? []).length > 0) return void 0;
|
|
602
|
+
const path = issue.path ?? [];
|
|
603
|
+
if (path[path.length - 1] !== "type") return void 0;
|
|
604
|
+
if (issue.discriminator !== void 0 && issue.discriminator !== "type") return void 0;
|
|
605
|
+
const literals = issue.options.filter((v) => typeof v === "string");
|
|
606
|
+
if (literals.length === 0) return void 0;
|
|
607
|
+
return noArmAccepts(path.slice(0, -1), literals, document);
|
|
608
|
+
}
|
|
609
|
+
function isAtTypeKey(issue) {
|
|
610
|
+
const path = issue.path ?? [];
|
|
611
|
+
return path.length === 1 && path[0] === "type";
|
|
612
|
+
}
|
|
613
|
+
function declaredTypeLiterals(armIssues) {
|
|
614
|
+
const literals = [];
|
|
615
|
+
let declares = false;
|
|
616
|
+
for (const issue of armIssues) {
|
|
617
|
+
if (isAtTypeKey(issue) && issue.code === "invalid_value" && Array.isArray(issue.values)) {
|
|
618
|
+
declares = true;
|
|
619
|
+
literals.push(...issue.values.filter((v) => typeof v === "string"));
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
if (isAtTypeKey(issue) && isUnion(issue) && Array.isArray(issue.options)) {
|
|
623
|
+
declares = true;
|
|
624
|
+
literals.push(...issue.options.filter((v) => typeof v === "string"));
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
if ((issue.path ?? []).length === 0 && isUnion(issue)) {
|
|
628
|
+
const nested = (issue.errors ?? []).map((sub) => declaredTypeLiterals(sub));
|
|
629
|
+
if (nested.length > 0 && nested.every((n) => n !== void 0)) {
|
|
630
|
+
declares = true;
|
|
631
|
+
for (const n of nested) literals.push(...n);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
658
634
|
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
635
|
+
return declares ? literals : void 0;
|
|
636
|
+
}
|
|
637
|
+
function explain(unionIssue, prefix, document) {
|
|
638
|
+
const arms = unionIssue.errors ?? [];
|
|
639
|
+
const declared = arms.map((arm) => declaredTypeLiterals(arm));
|
|
640
|
+
const declaringArms = declared.filter((d) => d !== void 0);
|
|
641
|
+
const acceptingIndexes = declared.map((d, i) => d === void 0 ? i : -1).filter((i) => i >= 0);
|
|
642
|
+
const expand = (armIssues, arm) => armIssues.flatMap((issue) => {
|
|
643
|
+
const absolute = [...prefix, ...issue.path ?? []];
|
|
644
|
+
const discriminated = noMatchingDiscriminator({ ...issue, path: absolute }, document);
|
|
645
|
+
if (discriminated) return [discriminated];
|
|
646
|
+
if (isUnion(issue)) return explain(issue, absolute, document);
|
|
647
|
+
return [
|
|
648
|
+
{
|
|
649
|
+
kind: "issue",
|
|
650
|
+
path: absolute,
|
|
651
|
+
message: issue.message ?? "",
|
|
652
|
+
code: issue.code,
|
|
653
|
+
...arm === void 0 ? {} : { arm }
|
|
654
|
+
}
|
|
655
|
+
];
|
|
666
656
|
});
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
657
|
+
if (declaringArms.length > 0 && acceptingIndexes.length === 1) {
|
|
658
|
+
return expand(arms[acceptingIndexes[0]]);
|
|
659
|
+
}
|
|
660
|
+
if (declaringArms.length > 0 && acceptingIndexes.length === 0) {
|
|
661
|
+
return [noArmAccepts(prefix, declaringArms.flat(), document)];
|
|
662
|
+
}
|
|
663
|
+
return arms.slice(0, MAX_UNION_ARMS_REPORTED).flatMap((arm, i) => expand(arm, `${i + 1}/${arms.length}`));
|
|
664
|
+
}
|
|
665
|
+
function explainUnionIssue(issue, document) {
|
|
666
|
+
const discriminated = noMatchingDiscriminator(issue, document);
|
|
667
|
+
if (discriminated) return [discriminated];
|
|
668
|
+
if (!isUnion(issue)) return [];
|
|
669
|
+
return explain(issue, issue.path ?? [], document);
|
|
670
|
+
}
|
|
671
|
+
function isTypeMismatch(issue) {
|
|
672
|
+
return isAtTypeKey(issue) && (issue.code === "invalid_value" || isUnion(issue));
|
|
673
|
+
}
|
|
674
|
+
function isShapeMismatch(issue) {
|
|
675
|
+
if ((issue.path ?? []).length !== 0) return false;
|
|
676
|
+
if (issue.code === "invalid_type") return true;
|
|
677
|
+
return isUnion(issue) && (issue.errors ?? []).every((arm) => !isViableArm(arm));
|
|
678
|
+
}
|
|
679
|
+
function isViableArm(armIssues) {
|
|
680
|
+
if (armIssues.some(isTypeMismatch)) return false;
|
|
681
|
+
return !armIssues.every(isShapeMismatch);
|
|
682
|
+
}
|
|
683
|
+
function findUndeclaredKeys(issues) {
|
|
684
|
+
const idOf = (finding) => JSON.stringify([...finding.path.map(String), finding.key]);
|
|
685
|
+
const collect = (list, prefix) => {
|
|
686
|
+
const found = [];
|
|
687
|
+
for (const issue of list) {
|
|
688
|
+
const path = [...prefix, ...issue.path ?? []];
|
|
689
|
+
if (issue.code === "unrecognized_keys") {
|
|
690
|
+
for (const key of issue.keys ?? []) found.push({ path, key });
|
|
691
|
+
}
|
|
692
|
+
if (isUnion(issue)) {
|
|
693
|
+
const perArm = (issue.errors ?? []).filter(isViableArm).map((arm) => collect(arm, path));
|
|
694
|
+
const [first, ...others] = perArm;
|
|
695
|
+
if (first === void 0) continue;
|
|
696
|
+
const refusedByAll = first.filter(
|
|
697
|
+
(finding) => others.every((arm) => arm.some((other) => idOf(other) === idOf(finding)))
|
|
698
|
+
);
|
|
699
|
+
found.push(...refusedByAll);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return found;
|
|
703
|
+
};
|
|
704
|
+
const seen = /* @__PURE__ */ new Set();
|
|
705
|
+
return collect(issues, []).filter((finding) => {
|
|
706
|
+
const id = idOf(finding);
|
|
707
|
+
if (seen.has(id)) return false;
|
|
708
|
+
seen.add(id);
|
|
709
|
+
return true;
|
|
671
710
|
});
|
|
672
|
-
child.on("exit", (code) => process.exit(code ?? 0));
|
|
673
711
|
}
|
|
674
712
|
|
|
675
|
-
// src/
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
713
|
+
// src/utils/authoring-face.ts
|
|
714
|
+
function validateAuthoredDocument(document) {
|
|
715
|
+
return StrictAnyComponentSchema.safeParse(document);
|
|
716
|
+
}
|
|
717
|
+
function describeUndeclaredKey(finding, document) {
|
|
718
|
+
const type = authoredTypeAt(document, finding.path);
|
|
719
|
+
const owner = type === void 0 ? "" : ` (type "${type}")`;
|
|
720
|
+
return `Undeclared key "${finding.key}" at ${formatIssuePath(finding.path)}${owner}: no schema declares it there. Remove it, or check its spelling against the keys declared at that position.`;
|
|
721
|
+
}
|
|
681
722
|
|
|
682
723
|
// src/utils/known-schema-types.ts
|
|
683
724
|
var KNOWN_SCHEMA_TYPES = [
|
|
@@ -690,7 +731,6 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
690
731
|
"action:icon",
|
|
691
732
|
"action:menu",
|
|
692
733
|
"address",
|
|
693
|
-
"advanced-chart",
|
|
694
734
|
"ai-form-assist",
|
|
695
735
|
"ai-recommendations",
|
|
696
736
|
"ai:feedback",
|
|
@@ -699,27 +739,21 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
699
739
|
"alert",
|
|
700
740
|
"alert-dialog",
|
|
701
741
|
"app",
|
|
702
|
-
"app-creation-wizard",
|
|
703
742
|
"app-schema-renderer",
|
|
704
743
|
"app-shell:cloud-connection:panel",
|
|
705
744
|
"app-shell:cloud:ai-model-status",
|
|
706
|
-
"app-shell:cloud:onboarding-next",
|
|
707
|
-
"app-shell:marketplace:installed-list",
|
|
708
745
|
"app-shell:mcp:connect-agent",
|
|
709
746
|
"app:launcher",
|
|
710
|
-
"area-chart",
|
|
711
747
|
"article",
|
|
712
748
|
"aside",
|
|
713
749
|
"aspect-ratio",
|
|
714
|
-
"auto_number",
|
|
715
750
|
"avatar",
|
|
716
751
|
"b",
|
|
717
752
|
"badge",
|
|
718
753
|
"bar-chart",
|
|
719
754
|
"blockquote",
|
|
720
|
-
"
|
|
755
|
+
"box",
|
|
721
756
|
"br",
|
|
722
|
-
"branding-editor",
|
|
723
757
|
"breadcrumb",
|
|
724
758
|
"button",
|
|
725
759
|
"button-group",
|
|
@@ -733,28 +767,22 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
733
767
|
"chatbot-enhanced",
|
|
734
768
|
"chatbot-floating",
|
|
735
769
|
"checkbox",
|
|
736
|
-
"
|
|
770
|
+
"checklist",
|
|
737
771
|
"cite",
|
|
738
772
|
"cloud-connection:panel",
|
|
739
773
|
"cloud:ai-model-status",
|
|
740
|
-
"cloud:
|
|
774
|
+
"cloud:workspace-timezone-notice",
|
|
741
775
|
"code",
|
|
742
776
|
"code-editor",
|
|
743
777
|
"collapsible",
|
|
744
|
-
"color",
|
|
745
778
|
"combobox",
|
|
746
779
|
"command",
|
|
747
780
|
"container",
|
|
748
781
|
"context-menu",
|
|
749
|
-
"currency",
|
|
750
782
|
"dashboard",
|
|
751
|
-
"dashboard-editor",
|
|
752
|
-
"dashboard-grid",
|
|
753
783
|
"data-model-designer",
|
|
754
784
|
"data-table",
|
|
755
|
-
"date",
|
|
756
785
|
"date-picker",
|
|
757
|
-
"datetime",
|
|
758
786
|
"dd",
|
|
759
787
|
"del",
|
|
760
788
|
"detail",
|
|
@@ -763,7 +791,6 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
763
791
|
"dialog",
|
|
764
792
|
"div",
|
|
765
793
|
"dl",
|
|
766
|
-
"donut-chart",
|
|
767
794
|
"drawer",
|
|
768
795
|
"dropdown-menu",
|
|
769
796
|
"dt",
|
|
@@ -813,8 +840,9 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
813
840
|
"field:object-ref",
|
|
814
841
|
"field:password",
|
|
815
842
|
"field:percent",
|
|
816
|
-
"field:permission-
|
|
843
|
+
"field:permission-ref",
|
|
817
844
|
"field:phone",
|
|
845
|
+
"field:position-ref",
|
|
818
846
|
"field:progress",
|
|
819
847
|
"field:qrcode",
|
|
820
848
|
"field:radio",
|
|
@@ -836,17 +864,12 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
836
864
|
"field:video",
|
|
837
865
|
"figcaption",
|
|
838
866
|
"figure",
|
|
839
|
-
"file",
|
|
840
867
|
"file-upload",
|
|
841
868
|
"filter-builder",
|
|
842
869
|
"filter-ui",
|
|
843
870
|
"flex",
|
|
844
871
|
"footer",
|
|
845
872
|
"form",
|
|
846
|
-
"form-analytics",
|
|
847
|
-
"formula",
|
|
848
|
-
"gantt",
|
|
849
|
-
"geolocation",
|
|
850
873
|
"global:notifications",
|
|
851
874
|
"global:search",
|
|
852
875
|
"grid",
|
|
@@ -858,6 +881,7 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
858
881
|
"h6",
|
|
859
882
|
"header",
|
|
860
883
|
"header-bar",
|
|
884
|
+
"hero",
|
|
861
885
|
"home",
|
|
862
886
|
"hover-card",
|
|
863
887
|
"hr",
|
|
@@ -866,47 +890,27 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
866
890
|
"icon",
|
|
867
891
|
"image",
|
|
868
892
|
"img",
|
|
869
|
-
"import-wizard",
|
|
870
893
|
"input",
|
|
871
894
|
"input-otp",
|
|
872
895
|
"ins",
|
|
873
|
-
"kanban",
|
|
874
|
-
"kanban-enhanced",
|
|
875
|
-
"kanban-ui",
|
|
876
896
|
"kbd",
|
|
877
897
|
"label",
|
|
878
898
|
"layout:app-schema-renderer",
|
|
879
|
-
"layout:navigation-renderer",
|
|
880
|
-
"layout:page-header",
|
|
881
899
|
"layout:page:card",
|
|
882
|
-
"layout:responsive-grid",
|
|
883
900
|
"li",
|
|
884
|
-
"line-chart",
|
|
885
901
|
"list",
|
|
886
902
|
"list-view",
|
|
887
903
|
"loading",
|
|
888
|
-
"location",
|
|
889
|
-
"lookup",
|
|
890
904
|
"main",
|
|
891
|
-
"map",
|
|
892
905
|
"mark",
|
|
893
906
|
"markdown",
|
|
894
|
-
"marketplace:installed-list",
|
|
895
|
-
"master_detail",
|
|
896
907
|
"mcp:connect-agent",
|
|
897
908
|
"menubar",
|
|
898
|
-
"metric",
|
|
899
|
-
"metric-card",
|
|
900
|
-
"multiselect",
|
|
901
909
|
"nav",
|
|
902
910
|
"nav:breadcrumb",
|
|
903
911
|
"nav:menu",
|
|
904
|
-
"navigation-designer",
|
|
905
912
|
"navigation-menu",
|
|
906
|
-
"navigation-renderer",
|
|
907
913
|
"nl-query",
|
|
908
|
-
"number",
|
|
909
|
-
"object",
|
|
910
914
|
"object-calendar",
|
|
911
915
|
"object-chart",
|
|
912
916
|
"object-data-table",
|
|
@@ -927,7 +931,6 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
927
931
|
"p",
|
|
928
932
|
"page",
|
|
929
933
|
"page-designer",
|
|
930
|
-
"page-header",
|
|
931
934
|
"page:accordion",
|
|
932
935
|
"page:card",
|
|
933
936
|
"page:footer",
|
|
@@ -937,57 +940,37 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
937
940
|
"page:tabs",
|
|
938
941
|
"pagination",
|
|
939
942
|
"password",
|
|
940
|
-
"percent",
|
|
941
|
-
"phone",
|
|
942
|
-
"pie-chart",
|
|
943
943
|
"pivot",
|
|
944
944
|
"plugin-calendar:calendar-view",
|
|
945
945
|
"plugin-calendar:object-calendar",
|
|
946
|
-
"plugin-charts:advanced-chart",
|
|
947
|
-
"plugin-charts:area-chart",
|
|
948
946
|
"plugin-charts:bar-chart",
|
|
949
947
|
"plugin-charts:chart",
|
|
950
948
|
"plugin-charts:chart:bar",
|
|
951
|
-
"plugin-charts:donut-chart",
|
|
952
|
-
"plugin-charts:line-chart",
|
|
953
949
|
"plugin-charts:object-chart",
|
|
954
|
-
"plugin-charts:pie-chart",
|
|
955
|
-
"plugin-charts:radar-chart",
|
|
956
|
-
"plugin-charts:scatter-chart",
|
|
957
950
|
"plugin-chatbot:chatbot",
|
|
958
951
|
"plugin-chatbot:chatbot-enhanced",
|
|
959
952
|
"plugin-chatbot:chatbot-floating",
|
|
960
953
|
"plugin-dashboard:dashboard",
|
|
961
|
-
"plugin-dashboard:dashboard-grid",
|
|
962
954
|
"plugin-dashboard:metric",
|
|
963
955
|
"plugin-dashboard:metric-card",
|
|
964
956
|
"plugin-dashboard:object-data-table",
|
|
965
957
|
"plugin-dashboard:object-metric",
|
|
966
958
|
"plugin-dashboard:object-pivot",
|
|
967
959
|
"plugin-dashboard:pivot",
|
|
968
|
-
"plugin-designer:app-creation-wizard",
|
|
969
|
-
"plugin-designer:branding-editor",
|
|
970
|
-
"plugin-designer:dashboard-editor",
|
|
971
960
|
"plugin-designer:data-model-designer",
|
|
972
961
|
"plugin-designer:field-designer",
|
|
973
|
-
"plugin-designer:navigation-designer",
|
|
974
962
|
"plugin-designer:object-manager",
|
|
975
963
|
"plugin-designer:page-designer",
|
|
976
964
|
"plugin-designer:process-designer",
|
|
977
965
|
"plugin-designer:report-designer",
|
|
978
966
|
"plugin-detail:detail-section",
|
|
979
967
|
"plugin-detail:detail-view",
|
|
980
|
-
"plugin-detail:related-list",
|
|
981
968
|
"plugin-editor:code-editor",
|
|
982
969
|
"plugin-form:embeddable-form",
|
|
983
|
-
"plugin-form:form-analytics",
|
|
984
970
|
"plugin-form:object-form",
|
|
985
971
|
"plugin-form:object-master-detail-form",
|
|
986
972
|
"plugin-gantt:object-gantt",
|
|
987
|
-
"plugin-grid:import-wizard",
|
|
988
973
|
"plugin-grid:object-grid",
|
|
989
|
-
"plugin-kanban:kanban-enhanced",
|
|
990
|
-
"plugin-kanban:kanban-ui",
|
|
991
974
|
"plugin-kanban:object-kanban",
|
|
992
975
|
"plugin-list:list-view",
|
|
993
976
|
"plugin-list:object-gallery",
|
|
@@ -995,12 +978,10 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
995
978
|
"plugin-markdown:markdown",
|
|
996
979
|
"plugin-report:report",
|
|
997
980
|
"plugin-report:report-viewer",
|
|
998
|
-
"plugin-report:spec-report",
|
|
999
981
|
"plugin-timeline:object-timeline",
|
|
1000
982
|
"plugin-timeline:timeline",
|
|
1001
983
|
"plugin-tree:object-tree",
|
|
1002
984
|
"plugin-view:object-view",
|
|
1003
|
-
"plugin-view:view",
|
|
1004
985
|
"plugin-view:view:simple",
|
|
1005
986
|
"popover",
|
|
1006
987
|
"pre",
|
|
@@ -1052,7 +1033,6 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1052
1033
|
"protocol-placeholder:global:search",
|
|
1053
1034
|
"protocol-placeholder:nav:breadcrumb",
|
|
1054
1035
|
"protocol-placeholder:nav:menu",
|
|
1055
|
-
"protocol-placeholder:page-header",
|
|
1056
1036
|
"protocol-placeholder:page:accordion",
|
|
1057
1037
|
"protocol-placeholder:page:card",
|
|
1058
1038
|
"protocol-placeholder:page:footer",
|
|
@@ -1065,7 +1045,6 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1065
1045
|
"protocol-placeholder:record:highlights",
|
|
1066
1046
|
"protocol-placeholder:record:path",
|
|
1067
1047
|
"protocol-placeholder:record:related_list",
|
|
1068
|
-
"protocol-placeholder:user:profile",
|
|
1069
1048
|
"protocol-placeholder:view:calendar",
|
|
1070
1049
|
"protocol-placeholder:view:drawer",
|
|
1071
1050
|
"protocol-placeholder:view:gallery",
|
|
@@ -1092,14 +1071,11 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1092
1071
|
"protocol-placeholder:widget:table",
|
|
1093
1072
|
"protocol-placeholder:widget:text",
|
|
1094
1073
|
"q",
|
|
1095
|
-
"qrcode",
|
|
1096
|
-
"radar-chart",
|
|
1097
|
-
"radio",
|
|
1098
1074
|
"radio-group",
|
|
1099
|
-
"rating",
|
|
1100
1075
|
"record",
|
|
1101
1076
|
"record:activity",
|
|
1102
1077
|
"record:alert",
|
|
1078
|
+
"record:approval_decision",
|
|
1103
1079
|
"record:approvals",
|
|
1104
1080
|
"record:attachments",
|
|
1105
1081
|
"record:chatter",
|
|
@@ -1112,55 +1088,35 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1112
1088
|
"record:quick_actions",
|
|
1113
1089
|
"record:reference_rail",
|
|
1114
1090
|
"record:related_list",
|
|
1115
|
-
"related-list",
|
|
1116
1091
|
"report",
|
|
1117
1092
|
"report-designer",
|
|
1118
1093
|
"report-viewer",
|
|
1119
|
-
"report:report",
|
|
1120
|
-
"report:report-viewer",
|
|
1121
|
-
"report:spec-report",
|
|
1122
1094
|
"resizable",
|
|
1123
|
-
"responsive-grid",
|
|
1124
|
-
"richtext",
|
|
1125
|
-
"scatter-chart",
|
|
1126
1095
|
"scroll-area",
|
|
1127
1096
|
"section",
|
|
1128
1097
|
"select",
|
|
1129
1098
|
"separator",
|
|
1130
|
-
"shared-view-link",
|
|
1131
1099
|
"sheet",
|
|
1132
1100
|
"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
1101
|
"skeleton",
|
|
1145
1102
|
"slider",
|
|
1146
1103
|
"small",
|
|
1147
1104
|
"sonner",
|
|
1148
1105
|
"sort-ui",
|
|
1149
1106
|
"span",
|
|
1150
|
-
"spec-report",
|
|
1151
1107
|
"spinner",
|
|
1152
1108
|
"stack",
|
|
1109
|
+
"stat",
|
|
1153
1110
|
"statistic",
|
|
1154
1111
|
"strong",
|
|
1155
1112
|
"sub",
|
|
1156
|
-
"summary",
|
|
1157
1113
|
"sup",
|
|
1158
1114
|
"switch",
|
|
1159
1115
|
"table",
|
|
1160
1116
|
"tabs",
|
|
1161
|
-
"tags",
|
|
1162
1117
|
"text",
|
|
1163
1118
|
"textarea",
|
|
1119
|
+
"tile-grid",
|
|
1164
1120
|
"time",
|
|
1165
1121
|
"timeline",
|
|
1166
1122
|
"toast",
|
|
@@ -1168,7 +1124,6 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1168
1124
|
"toggle",
|
|
1169
1125
|
"toggle-group",
|
|
1170
1126
|
"tooltip",
|
|
1171
|
-
"tree",
|
|
1172
1127
|
"tree-view",
|
|
1173
1128
|
"u",
|
|
1174
1129
|
"ui:a",
|
|
@@ -1177,6 +1132,7 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1177
1132
|
"ui:address",
|
|
1178
1133
|
"ui:alert",
|
|
1179
1134
|
"ui:alert-dialog",
|
|
1135
|
+
"ui:app",
|
|
1180
1136
|
"ui:article",
|
|
1181
1137
|
"ui:aside",
|
|
1182
1138
|
"ui:aspect-ratio",
|
|
@@ -1184,6 +1140,7 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1184
1140
|
"ui:b",
|
|
1185
1141
|
"ui:badge",
|
|
1186
1142
|
"ui:blockquote",
|
|
1143
|
+
"ui:box",
|
|
1187
1144
|
"ui:br",
|
|
1188
1145
|
"ui:breadcrumb",
|
|
1189
1146
|
"ui:button",
|
|
@@ -1193,6 +1150,7 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1193
1150
|
"ui:carousel",
|
|
1194
1151
|
"ui:checkbox",
|
|
1195
1152
|
"ui:cite",
|
|
1153
|
+
"ui:code",
|
|
1196
1154
|
"ui:collapsible",
|
|
1197
1155
|
"ui:combobox",
|
|
1198
1156
|
"ui:command",
|
|
@@ -1226,6 +1184,7 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1226
1184
|
"ui:h6",
|
|
1227
1185
|
"ui:header",
|
|
1228
1186
|
"ui:header-bar",
|
|
1187
|
+
"ui:home",
|
|
1229
1188
|
"ui:hover-card",
|
|
1230
1189
|
"ui:hr",
|
|
1231
1190
|
"ui:html",
|
|
@@ -1248,6 +1207,7 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1248
1207
|
"ui:navigation-menu",
|
|
1249
1208
|
"ui:ol",
|
|
1250
1209
|
"ui:p",
|
|
1210
|
+
"ui:page",
|
|
1251
1211
|
"ui:pagination",
|
|
1252
1212
|
"ui:password",
|
|
1253
1213
|
"ui:popover",
|
|
@@ -1255,6 +1215,7 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1255
1215
|
"ui:progress",
|
|
1256
1216
|
"ui:q",
|
|
1257
1217
|
"ui:radio-group",
|
|
1218
|
+
"ui:record",
|
|
1258
1219
|
"ui:resizable",
|
|
1259
1220
|
"ui:scroll-area",
|
|
1260
1221
|
"ui:section",
|
|
@@ -1262,16 +1223,6 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1262
1223
|
"ui:separator",
|
|
1263
1224
|
"ui:sheet",
|
|
1264
1225
|
"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
1226
|
"ui:skeleton",
|
|
1276
1227
|
"ui:slider",
|
|
1277
1228
|
"ui:small",
|
|
@@ -1297,17 +1248,13 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1297
1248
|
"ui:tree-view",
|
|
1298
1249
|
"ui:u",
|
|
1299
1250
|
"ui:ul",
|
|
1251
|
+
"ui:utility",
|
|
1300
1252
|
"ul",
|
|
1301
|
-
"
|
|
1302
|
-
"user",
|
|
1303
|
-
"user:profile",
|
|
1253
|
+
"usage-bar",
|
|
1304
1254
|
"utility",
|
|
1305
|
-
"vector",
|
|
1306
|
-
"view",
|
|
1307
1255
|
"view-switcher",
|
|
1308
1256
|
"view:calendar",
|
|
1309
1257
|
"view:chart",
|
|
1310
|
-
"view:dashboard",
|
|
1311
1258
|
"view:detail",
|
|
1312
1259
|
"view:drawer",
|
|
1313
1260
|
"view:filter-ui",
|
|
@@ -1319,13 +1266,11 @@ var KNOWN_SCHEMA_TYPES = [
|
|
|
1319
1266
|
"view:list",
|
|
1320
1267
|
"view:map",
|
|
1321
1268
|
"view:modal",
|
|
1322
|
-
"view:shared-view-link",
|
|
1323
1269
|
"view:simple",
|
|
1324
1270
|
"view:sort-ui",
|
|
1325
1271
|
"view:split",
|
|
1326
1272
|
"view:tabbed",
|
|
1327
1273
|
"view:timeline",
|
|
1328
|
-
"view:tree",
|
|
1329
1274
|
"view:view-switcher",
|
|
1330
1275
|
"view:wizard",
|
|
1331
1276
|
"widget:bar",
|
|
@@ -1346,9 +1291,93 @@ function isKnownSchemaType(type) {
|
|
|
1346
1291
|
return KNOWN_SCHEMA_TYPE_SET.has(type);
|
|
1347
1292
|
}
|
|
1348
1293
|
|
|
1294
|
+
// src/utils/known-type-case-suggestion.ts
|
|
1295
|
+
function suggestKnownTypeByCase(type) {
|
|
1296
|
+
if (typeof type !== "string" || type === "") return void 0;
|
|
1297
|
+
const wanted = type.toLowerCase();
|
|
1298
|
+
for (const candidate of KNOWN_SCHEMA_TYPES) {
|
|
1299
|
+
if (candidate !== type && candidate.toLowerCase() === wanted) return candidate;
|
|
1300
|
+
}
|
|
1301
|
+
return void 0;
|
|
1302
|
+
}
|
|
1303
|
+
function didYouMeanClause(type) {
|
|
1304
|
+
const match = suggestKnownTypeByCase(type);
|
|
1305
|
+
return match === void 0 ? "" : ` \u2014 did you mean "${match}"?`;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
// src/utils/unbindable-text-expressions.ts
|
|
1309
|
+
import {
|
|
1310
|
+
EXPRESSION_BINDABLE_TEXT_KEYS,
|
|
1311
|
+
expressionBindableTextKeysFor
|
|
1312
|
+
} from "@objectstack/spec/ui";
|
|
1313
|
+
import { nodeSlotValues, nodeSlotsFor } from "@object-ui/types";
|
|
1314
|
+
var EXPRESSION_PATTERN = /\$\{[^}]+\}/;
|
|
1315
|
+
var COMPOSITION_KEY = "children";
|
|
1316
|
+
var PAGE_DOCUMENT_ROOT_TYPE = "page";
|
|
1317
|
+
function isComponentNode(value) {
|
|
1318
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.type === "string";
|
|
1319
|
+
}
|
|
1320
|
+
function judge(node, path, into) {
|
|
1321
|
+
const evaluatedKeys = expressionBindableTextKeysFor(node.type);
|
|
1322
|
+
for (const key of EXPRESSION_BINDABLE_TEXT_KEYS) {
|
|
1323
|
+
const value = node[key];
|
|
1324
|
+
if (typeof value !== "string" || !EXPRESSION_PATTERN.test(value)) continue;
|
|
1325
|
+
if (evaluatedKeys.includes(key)) continue;
|
|
1326
|
+
into.push({
|
|
1327
|
+
severity: isKnownSchemaType(node.type) ? "refusal" : "warning",
|
|
1328
|
+
path: [...path, key],
|
|
1329
|
+
type: node.type,
|
|
1330
|
+
key,
|
|
1331
|
+
evaluatedKeys
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
function visit(node, path, isDocumentRoot, into) {
|
|
1336
|
+
if (!(isDocumentRoot && node.type === PAGE_DOCUMENT_ROOT_TYPE)) {
|
|
1337
|
+
judge(node, path, into);
|
|
1338
|
+
}
|
|
1339
|
+
const children = node[COMPOSITION_KEY];
|
|
1340
|
+
if (Array.isArray(children)) {
|
|
1341
|
+
children.forEach((child, index) => {
|
|
1342
|
+
if (isComponentNode(child)) visit(child, [...path, COMPOSITION_KEY, index], false, into);
|
|
1343
|
+
});
|
|
1344
|
+
} else if (isComponentNode(children)) {
|
|
1345
|
+
visit(children, [...path, COMPOSITION_KEY], false, into);
|
|
1346
|
+
}
|
|
1347
|
+
for (const slot of nodeSlotsFor(node.type)) {
|
|
1348
|
+
for (const { segments, value } of nodeSlotValues(node, slot.path)) {
|
|
1349
|
+
if (isComponentNode(value)) visit(value, [...path, ...segments], false, into);
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
function findUnbindableTextExpressions(document) {
|
|
1354
|
+
const found = [];
|
|
1355
|
+
if (isComponentNode(document)) visit(document, [], true, found);
|
|
1356
|
+
return found;
|
|
1357
|
+
}
|
|
1358
|
+
var inCode = (key) => "`" + key + "`";
|
|
1359
|
+
function describeUnbindableTextExpression(finding) {
|
|
1360
|
+
const at = formatIssuePath(finding.path);
|
|
1361
|
+
if (finding.severity === "warning") {
|
|
1362
|
+
return `at ${at}: "${finding.type}" is not a registered component, so the expression on ${inCode(finding.key)} is not refused; a custom renderer may evaluate it itself.`;
|
|
1363
|
+
}
|
|
1364
|
+
const evaluates = finding.evaluatedKeys.length > 0 ? `it evaluates only ${finding.evaluatedKeys.map(inCode).join(", ")}` : `it evaluates none of ${EXPRESSION_BINDABLE_TEXT_KEYS.map(inCode).join(", ")}`;
|
|
1365
|
+
return `at ${at}: "${finding.type}" never evaluates ${inCode(finding.key)} (${evaluates}), so the expression is never resolved: the user sees its literal text, or nothing.`;
|
|
1366
|
+
}
|
|
1367
|
+
function workingChannels(finding) {
|
|
1368
|
+
const channels = [
|
|
1369
|
+
...finding.evaluatedKeys.map(inCode),
|
|
1370
|
+
inCode("content"),
|
|
1371
|
+
`${inCode(`properties.${finding.key}`)} (evaluated, then hoisted onto the node)`
|
|
1372
|
+
];
|
|
1373
|
+
return `Channels SchemaRenderer evaluates: ${channels.join(", ")}; or resolve the value in the host before the schema reaches SchemaRenderer.`;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1349
1376
|
// src/commands/check.ts
|
|
1350
1377
|
var OBJECTUI_STRUCTURAL_KEYS = [
|
|
1351
1378
|
// Composition — the `children`/`body`-class keys the ruling names.
|
|
1379
|
+
// `body` is the RETIRED spelling, kept so old files are still identified and
|
|
1380
|
+
// then refused — see the docblock above (objectui#6771).
|
|
1352
1381
|
"body",
|
|
1353
1382
|
"children",
|
|
1354
1383
|
// Presentation.
|
|
@@ -1367,8 +1396,24 @@ var OBJECTUI_STRUCTURAL_KEYS = [
|
|
|
1367
1396
|
"testId",
|
|
1368
1397
|
"ariaLabel"
|
|
1369
1398
|
];
|
|
1370
|
-
function
|
|
1371
|
-
|
|
1399
|
+
function recogniseObjectUiSchemaFile(content) {
|
|
1400
|
+
if (OBJECTUI_STRUCTURAL_KEYS.some((key) => key in content)) {
|
|
1401
|
+
return { recognised: true, validated: false };
|
|
1402
|
+
}
|
|
1403
|
+
const result = validateAuthoredDocument(content);
|
|
1404
|
+
return result.success ? { recognised: true, validated: true } : { recognised: false, issues: result.error.issues };
|
|
1405
|
+
}
|
|
1406
|
+
function describeFirstIssue(issues) {
|
|
1407
|
+
const [first] = issues;
|
|
1408
|
+
if (first === void 0) return void 0;
|
|
1409
|
+
const lead = issues.length === 1 ? "Issue" : `First of ${issues.length} issues`;
|
|
1410
|
+
return `${lead} at ${formatIssuePath(first.path)}: ${first.message}`;
|
|
1411
|
+
}
|
|
1412
|
+
function closingLine(tally) {
|
|
1413
|
+
return `ObjectUI schema files: ${tally.validated} validated, ${tally.notValidated} recognised but not validated, ${tally.didNotValidate} did not validate. This sweep is advisory; run \`objectui validate <file>\` for a verdict.`;
|
|
1414
|
+
}
|
|
1415
|
+
function isUnvalidatedCandidate(type) {
|
|
1416
|
+
return isKnownSchemaType(type);
|
|
1372
1417
|
}
|
|
1373
1418
|
function describeParseError(text, error) {
|
|
1374
1419
|
const upTo = text.slice(0, error.offset);
|
|
@@ -1377,69 +1422,158 @@ function describeParseError(text, error) {
|
|
|
1377
1422
|
return `${printParseErrorCode(error.error)} at line ${line} column ${column}`;
|
|
1378
1423
|
}
|
|
1379
1424
|
async function check(cwd = process.cwd()) {
|
|
1380
|
-
console.log(
|
|
1425
|
+
console.log(chalk6.bold("Object UI Schema Check"));
|
|
1381
1426
|
const files = globSync("**/*.{json,yaml,yml}", {
|
|
1382
1427
|
cwd,
|
|
1383
|
-
ignore
|
|
1428
|
+
// `glob` matches `ignore` patterns against the path relative to `cwd`, so
|
|
1429
|
+
// an unanchored `dist/**`/`node_modules/**` excludes only a directory of
|
|
1430
|
+
// that name at the scan root — every nested `packages/*/dist/`,
|
|
1431
|
+
// `examples/*/dist/`, `apps/*/dist/` (and their `node_modules/`) is still
|
|
1432
|
+
// scanned. `**/` anchors the match at any depth (objectui#6320): measured
|
|
1433
|
+
// on this repository, a built tree without it reports roughly double the
|
|
1434
|
+
// files of a clean checkout, almost all of it re-reading the author's own
|
|
1435
|
+
// schemas from build output.
|
|
1436
|
+
ignore: ["**/node_modules/**", "**/dist/**", ".git/**"]
|
|
1384
1437
|
});
|
|
1385
1438
|
console.log(`Analyzing ${files.length} files...`);
|
|
1386
1439
|
let errors = 0;
|
|
1387
1440
|
let skipped = 0;
|
|
1441
|
+
const unvalidatedCandidates = [];
|
|
1442
|
+
let validated = 0;
|
|
1443
|
+
let notValidated = 0;
|
|
1444
|
+
const judgeTextExpressions = (file, document) => {
|
|
1445
|
+
for (const finding of findUnbindableTextExpressions(document)) {
|
|
1446
|
+
const line = `${file} ${describeUnbindableTextExpression(finding)}`;
|
|
1447
|
+
if (finding.severity === "refusal") {
|
|
1448
|
+
console.log(chalk6.red(`x Unevaluated expression in ${line}`));
|
|
1449
|
+
console.log(chalk6.dim(` ${workingChannels(finding)}`));
|
|
1450
|
+
errors++;
|
|
1451
|
+
} else {
|
|
1452
|
+
console.log(chalk6.yellow(`\u26A0\uFE0F Expression not judged in ${line}`));
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1388
1456
|
for (const file of files) {
|
|
1389
1457
|
try {
|
|
1390
1458
|
if (file.endsWith(".json")) {
|
|
1391
|
-
const text = readFileSync2(
|
|
1459
|
+
const text = readFileSync2(join6(cwd, file), "utf-8");
|
|
1392
1460
|
const parseErrors = [];
|
|
1393
1461
|
const content = parseJsonc(text, parseErrors, { allowTrailingComma: true });
|
|
1394
1462
|
if (parseErrors.length > 0) {
|
|
1395
1463
|
const [first] = parseErrors;
|
|
1396
1464
|
console.log(
|
|
1397
|
-
|
|
1465
|
+
chalk6.red(`x Invalid JSON in ${file}: ${describeParseError(text, first)}`)
|
|
1398
1466
|
);
|
|
1399
1467
|
errors++;
|
|
1400
1468
|
continue;
|
|
1401
1469
|
}
|
|
1402
1470
|
if (content && typeof content === "object" && content.type) {
|
|
1403
1471
|
if (typeof content.type === "string") {
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1472
|
+
const recognition = recogniseObjectUiSchemaFile(
|
|
1473
|
+
content
|
|
1474
|
+
);
|
|
1475
|
+
if (!recognition.recognised) {
|
|
1476
|
+
if (isUnvalidatedCandidate(content.type)) {
|
|
1477
|
+
unvalidatedCandidates.push({
|
|
1478
|
+
file,
|
|
1479
|
+
type: content.type,
|
|
1480
|
+
issues: recognition.issues,
|
|
1481
|
+
document: content
|
|
1482
|
+
});
|
|
1483
|
+
judgeTextExpressions(file, content);
|
|
1484
|
+
} else {
|
|
1485
|
+
skipped++;
|
|
1486
|
+
}
|
|
1487
|
+
continue;
|
|
1408
1488
|
}
|
|
1489
|
+
if (recognition.validated) {
|
|
1490
|
+
validated++;
|
|
1491
|
+
} else {
|
|
1492
|
+
notValidated++;
|
|
1493
|
+
}
|
|
1494
|
+
if (!isKnownSchemaType(content.type)) {
|
|
1495
|
+
console.log(
|
|
1496
|
+
chalk6.yellow(
|
|
1497
|
+
`\u26A0\uFE0F Unknown schema type "${content.type}" in ${file}` + didYouMeanClause(content.type)
|
|
1498
|
+
)
|
|
1499
|
+
);
|
|
1500
|
+
}
|
|
1501
|
+
judgeTextExpressions(file, content);
|
|
1409
1502
|
}
|
|
1410
1503
|
}
|
|
1411
1504
|
}
|
|
1412
1505
|
} catch (e) {
|
|
1413
|
-
console.log(
|
|
1506
|
+
console.log(chalk6.red(`x Invalid JSON in ${file}: ${e.message}`));
|
|
1414
1507
|
errors++;
|
|
1415
1508
|
}
|
|
1416
1509
|
}
|
|
1510
|
+
if (unvalidatedCandidates.length > 0) {
|
|
1511
|
+
const n = unvalidatedCandidates.length;
|
|
1512
|
+
console.log(
|
|
1513
|
+
chalk6.yellow(
|
|
1514
|
+
`\u26A0\uFE0F ${n} file${n === 1 ? "" : "s"} carr${n === 1 ? "ies" : "y"} a registered ObjectUI component type but did not validate as an ObjectUI schema:`
|
|
1515
|
+
)
|
|
1516
|
+
);
|
|
1517
|
+
for (const { file, type, issues, document } of unvalidatedCandidates) {
|
|
1518
|
+
console.log(chalk6.yellow(` ${file} (type "${type}")`));
|
|
1519
|
+
const firstIssue = describeFirstIssue(issues);
|
|
1520
|
+
if (firstIssue !== void 0) {
|
|
1521
|
+
console.log(chalk6.yellow(` ${firstIssue}`));
|
|
1522
|
+
}
|
|
1523
|
+
for (const finding of findUndeclaredKeys(issues)) {
|
|
1524
|
+
console.log(chalk6.yellow(` ${describeUndeclaredKey(finding, document)}`));
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
console.log(
|
|
1528
|
+
chalk6.dim(" Run `objectui validate <file>` on any of them for the full diagnosis.")
|
|
1529
|
+
);
|
|
1530
|
+
console.log(
|
|
1531
|
+
chalk6.dim(
|
|
1532
|
+
" Either the document is off-spec, or its component type is not modelled by @object-ui/types."
|
|
1533
|
+
)
|
|
1534
|
+
);
|
|
1535
|
+
console.log(
|
|
1536
|
+
chalk6.dim(
|
|
1537
|
+
" These are NOT counted as skipped: a schema that fails validation is a broken schema, not a foreign file."
|
|
1538
|
+
)
|
|
1539
|
+
);
|
|
1540
|
+
}
|
|
1417
1541
|
if (skipped > 0) {
|
|
1418
1542
|
console.log(
|
|
1419
|
-
|
|
1420
|
-
`Skipped ${skipped} file${skipped === 1 ? "" : "s"} with a root "type"
|
|
1543
|
+
chalk6.dim(
|
|
1544
|
+
`Skipped ${skipped} file${skipped === 1 ? "" : "s"} with a root "type" that no ObjectUI recogniser admitted.`
|
|
1421
1545
|
)
|
|
1422
1546
|
);
|
|
1423
1547
|
console.log(
|
|
1424
|
-
|
|
1548
|
+
chalk6.dim(
|
|
1425
1549
|
` A file is checked when its root carries an ObjectUI structural key: ${OBJECTUI_STRUCTURAL_KEYS.join(", ")}.`
|
|
1426
1550
|
)
|
|
1427
1551
|
);
|
|
1552
|
+
console.log(
|
|
1553
|
+
chalk6.dim(
|
|
1554
|
+
" It is also checked when the whole document validates as an ObjectUI component schema."
|
|
1555
|
+
)
|
|
1556
|
+
);
|
|
1428
1557
|
}
|
|
1429
1558
|
if (errors === 0) {
|
|
1430
|
-
console.log(
|
|
1559
|
+
console.log(
|
|
1560
|
+
closingLine({
|
|
1561
|
+
validated,
|
|
1562
|
+
notValidated,
|
|
1563
|
+
didNotValidate: unvalidatedCandidates.length
|
|
1564
|
+
})
|
|
1565
|
+
);
|
|
1431
1566
|
} else {
|
|
1432
|
-
console.log(
|
|
1567
|
+
console.log(chalk6.red(`Found ${errors} errors`));
|
|
1433
1568
|
process.exit(1);
|
|
1434
1569
|
}
|
|
1435
1570
|
}
|
|
1436
1571
|
|
|
1437
1572
|
// src/commands/validate.ts
|
|
1438
|
-
import
|
|
1439
|
-
import { readFileSync as readFileSync3, existsSync as
|
|
1440
|
-
import { resolve as
|
|
1573
|
+
import chalk7 from "chalk";
|
|
1574
|
+
import { readFileSync as readFileSync3, existsSync as existsSync5 } from "fs";
|
|
1575
|
+
import { resolve as resolve3 } from "path";
|
|
1441
1576
|
import { load as loadYaml } from "js-yaml";
|
|
1442
|
-
import { safeValidateSchema } from "@object-ui/types/zod";
|
|
1443
1577
|
|
|
1444
1578
|
// src/utils/spec-vocabulary-hint.ts
|
|
1445
1579
|
function findSpecVocabularyFormFields(node, path = "") {
|
|
@@ -1470,81 +1604,165 @@ function findSpecVocabularyFormFields(node, path = "") {
|
|
|
1470
1604
|
return findings;
|
|
1471
1605
|
}
|
|
1472
1606
|
|
|
1607
|
+
// src/utils/record-block-binding-hint.ts
|
|
1608
|
+
var ONE_RECORD_BLOCK_TYPES = /* @__PURE__ */ new Set([
|
|
1609
|
+
"record:details",
|
|
1610
|
+
"record:highlights",
|
|
1611
|
+
"record:quick_actions"
|
|
1612
|
+
]);
|
|
1613
|
+
var PARENT_BINDING_BLOCK_TYPE = "record:related_list";
|
|
1614
|
+
var isRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
1615
|
+
var unboundedObjectOf = (binding) => isRecord(binding) && typeof binding.object === "string" && binding.object.length > 0 && binding.limit !== 1 ? binding.object : void 0;
|
|
1616
|
+
function findRecordBindingsWithoutLimitOne(document, path = []) {
|
|
1617
|
+
if (Array.isArray(document)) {
|
|
1618
|
+
return document.flatMap((child, i) => findRecordBindingsWithoutLimitOne(child, [...path, i]));
|
|
1619
|
+
}
|
|
1620
|
+
if (!isRecord(document)) return [];
|
|
1621
|
+
const findings = [];
|
|
1622
|
+
if (typeof document.type === "string" && ONE_RECORD_BLOCK_TYPES.has(document.type)) {
|
|
1623
|
+
const object = unboundedObjectOf(document.dataSource);
|
|
1624
|
+
if (object) findings.push({ path: formatIssuePath(path), type: document.type, object, key: "dataSource" });
|
|
1625
|
+
}
|
|
1626
|
+
if (document.type === PARENT_BINDING_BLOCK_TYPE && isRecord(document.properties)) {
|
|
1627
|
+
const object = unboundedObjectOf(document.properties.parentDataSource);
|
|
1628
|
+
if (object) {
|
|
1629
|
+
findings.push({ path: formatIssuePath(path), type: document.type, object, key: "properties.parentDataSource" });
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
for (const [key, value] of Object.entries(document)) {
|
|
1633
|
+
findings.push(...findRecordBindingsWithoutLimitOne(value, [...path, key]));
|
|
1634
|
+
}
|
|
1635
|
+
return findings;
|
|
1636
|
+
}
|
|
1637
|
+
function describeRecordBindingWithoutLimitOne(finding) {
|
|
1638
|
+
if (finding.key === "properties.parentDataSource") {
|
|
1639
|
+
return `${finding.path}: ${finding.type}'s parent record is bound to "${finding.object}" by a \`properties.parentDataSource\` without \`limit: 1\`. A related list hangs off ONE parent record \u2014 the first row of the binding by its \`sort\` \u2014 so declare \`limit: 1\` (and a \`sort\` when several rows can match) to say which record that is.`;
|
|
1640
|
+
}
|
|
1641
|
+
return `${finding.path}: ${finding.type} is bound to "${finding.object}" by a dataSource without \`limit: 1\`. A record block shows ONE record \u2014 the first row of the binding by its \`sort\` \u2014 so declare \`limit: 1\` (and a \`sort\` when several rows can match) to say which record that is.`;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1473
1644
|
// src/commands/validate.ts
|
|
1474
1645
|
async function validate(schemaPath) {
|
|
1475
|
-
console.log(
|
|
1476
|
-
const resolvedPath =
|
|
1477
|
-
if (!
|
|
1478
|
-
console.error(
|
|
1646
|
+
console.log(chalk7.blue("\u{1F50D} ObjectUI Schema Validator\n"));
|
|
1647
|
+
const resolvedPath = resolve3(process.cwd(), schemaPath);
|
|
1648
|
+
if (!existsSync5(resolvedPath)) {
|
|
1649
|
+
console.error(chalk7.red(`\u2717 Error: Schema file not found: ${schemaPath}`));
|
|
1479
1650
|
process.exit(1);
|
|
1480
1651
|
}
|
|
1481
1652
|
try {
|
|
1482
1653
|
const fileContent = readFileSync3(resolvedPath, "utf-8");
|
|
1483
1654
|
let schema;
|
|
1484
1655
|
if (schemaPath.endsWith(".yaml") || schemaPath.endsWith(".yml")) {
|
|
1485
|
-
console.log(
|
|
1656
|
+
console.log(chalk7.gray(`Reading YAML schema from: ${schemaPath}`));
|
|
1486
1657
|
schema = loadYaml(fileContent);
|
|
1487
1658
|
} else if (schemaPath.endsWith(".json")) {
|
|
1488
|
-
console.log(
|
|
1659
|
+
console.log(chalk7.gray(`Reading JSON schema from: ${schemaPath}`));
|
|
1489
1660
|
schema = JSON.parse(fileContent);
|
|
1490
1661
|
} else {
|
|
1491
1662
|
try {
|
|
1492
1663
|
schema = JSON.parse(fileContent);
|
|
1493
|
-
console.log(
|
|
1664
|
+
console.log(chalk7.gray(`Reading schema from: ${schemaPath} (detected as JSON)`));
|
|
1494
1665
|
} catch {
|
|
1495
1666
|
schema = loadYaml(fileContent);
|
|
1496
|
-
console.log(
|
|
1667
|
+
console.log(chalk7.gray(`Reading schema from: ${schemaPath} (detected as YAML)`));
|
|
1497
1668
|
}
|
|
1498
1669
|
}
|
|
1499
|
-
console.log(
|
|
1500
|
-
const result =
|
|
1670
|
+
console.log(chalk7.gray("Validating schema...\n"));
|
|
1671
|
+
const result = validateAuthoredDocument(schema);
|
|
1501
1672
|
if (result.success) {
|
|
1502
|
-
console.log(
|
|
1673
|
+
console.log(chalk7.green("\u2713 Schema is valid!\n"));
|
|
1503
1674
|
const data = result.data;
|
|
1504
|
-
console.log(
|
|
1505
|
-
console.log(
|
|
1675
|
+
console.log(chalk7.bold("Schema Information:"));
|
|
1676
|
+
console.log(chalk7.gray(" Type:"), data.type || "unknown");
|
|
1506
1677
|
if (data.id) {
|
|
1507
|
-
console.log(
|
|
1678
|
+
console.log(chalk7.gray(" ID:"), data.id);
|
|
1508
1679
|
}
|
|
1509
|
-
|
|
1510
|
-
|
|
1680
|
+
const title = "title" in data ? data.title : void 0;
|
|
1681
|
+
if (data.label || title) {
|
|
1682
|
+
console.log(chalk7.gray(" Label:"), data.label || title);
|
|
1511
1683
|
}
|
|
1512
1684
|
if (data.children && Array.isArray(data.children)) {
|
|
1513
|
-
console.log(
|
|
1685
|
+
console.log(chalk7.gray(" Children:"), data.children.length);
|
|
1514
1686
|
}
|
|
1515
1687
|
const mixed = findSpecVocabularyFormFields(schema).filter((f) => f.mixedName);
|
|
1516
|
-
|
|
1517
|
-
|
|
1688
|
+
const unboundedRecordBindings = findRecordBindingsWithoutLimitOne(schema);
|
|
1689
|
+
if (mixed.length > 0 || unboundedRecordBindings.length > 0) {
|
|
1690
|
+
console.log(chalk7.yellow("\nWarnings:"));
|
|
1518
1691
|
for (const m of mixed) {
|
|
1519
|
-
console.log(
|
|
1692
|
+
console.log(chalk7.yellow(
|
|
1520
1693
|
` ${m.path}: '${m.mixedName}' also carries { field: '${m.field}' } \u2014 mixed form-field vocabularies. The renderer ignores \`field\` here; drop one of the two.`
|
|
1521
1694
|
));
|
|
1522
1695
|
}
|
|
1696
|
+
for (const finding of unboundedRecordBindings) {
|
|
1697
|
+
console.log(chalk7.yellow(` ${describeRecordBindingWithoutLimitOne(finding)}`));
|
|
1698
|
+
}
|
|
1523
1699
|
}
|
|
1524
1700
|
console.log("");
|
|
1525
1701
|
process.exit(0);
|
|
1526
1702
|
} else {
|
|
1527
|
-
console.error(
|
|
1528
|
-
console.error(
|
|
1703
|
+
console.error(chalk7.red("\u2717 Schema validation failed!\n"));
|
|
1704
|
+
console.error(chalk7.bold("Validation Errors:"));
|
|
1529
1705
|
result.error.issues.forEach((issue, index) => {
|
|
1530
|
-
console.error(
|
|
1706
|
+
console.error(chalk7.red(`
|
|
1531
1707
|
${index + 1}. ${issue.message}`));
|
|
1532
|
-
|
|
1533
|
-
console.error(chalk11.gray(` Path: ${issue.path.join(" \u2192 ")}`));
|
|
1534
|
-
}
|
|
1708
|
+
console.error(chalk7.gray(` Path: ${formatIssuePath(issue.path)}`));
|
|
1535
1709
|
if (issue.code) {
|
|
1536
|
-
console.error(
|
|
1710
|
+
console.error(chalk7.gray(` Code: ${issue.code}`));
|
|
1537
1711
|
}
|
|
1712
|
+
explainUnionIssue(issue, schema).forEach((line, sub) => {
|
|
1713
|
+
const where = formatIssuePath(line.path);
|
|
1714
|
+
if (line.kind === "note") {
|
|
1715
|
+
const at = line.path.length > 0 ? ` at ${where}` : "";
|
|
1716
|
+
if (line.authoredType === void 0) {
|
|
1717
|
+
console.error(
|
|
1718
|
+
chalk7.yellow(
|
|
1719
|
+
` No \`type\` is declared${at}, so none of the ${line.totalArmNames} accepted component types can be selected.`
|
|
1720
|
+
)
|
|
1721
|
+
);
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1724
|
+
console.error(
|
|
1725
|
+
chalk7.yellow(` No arm accepts type "${line.authoredType}"${at}.`)
|
|
1726
|
+
);
|
|
1727
|
+
if (line.candidates.length > 0) {
|
|
1728
|
+
console.error(
|
|
1729
|
+
chalk7.gray(
|
|
1730
|
+
` Nearest of the ${line.totalArmNames} accepted types: ` + line.candidates.join(", ")
|
|
1731
|
+
)
|
|
1732
|
+
);
|
|
1733
|
+
}
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
const arm = line.arm === void 0 ? "" : `[arm ${line.arm}] `;
|
|
1737
|
+
console.error(chalk7.red(` ${index + 1}.${sub + 1} ${arm}${line.message}`));
|
|
1738
|
+
console.error(chalk7.gray(` Path: ${where}`));
|
|
1739
|
+
if (line.code) {
|
|
1740
|
+
console.error(chalk7.gray(` Code: ${line.code}`));
|
|
1741
|
+
}
|
|
1742
|
+
});
|
|
1538
1743
|
});
|
|
1744
|
+
const undeclared = findUndeclaredKeys(result.error.issues);
|
|
1745
|
+
if (undeclared.length > 0) {
|
|
1746
|
+
console.error(chalk7.bold("\nUndeclared keys \u2014 the strict authoring face refuses them:"));
|
|
1747
|
+
for (const finding of undeclared) {
|
|
1748
|
+
console.error(chalk7.yellow(` ${describeUndeclaredKey(finding, schema)}`));
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
const mixedHere = findSpecVocabularyFormFields(schema).filter((f) => f.mixedName);
|
|
1752
|
+
for (const m of mixedHere) {
|
|
1753
|
+
console.error(chalk7.yellow(
|
|
1754
|
+
` ${m.path}: '${m.mixedName}' also carries { field: '${m.field}' } \u2014 mixed form-field vocabularies. The renderer ignores \`field\` here; drop one of the two.`
|
|
1755
|
+
));
|
|
1756
|
+
}
|
|
1539
1757
|
const specShaped = findSpecVocabularyFormFields(schema).filter((f) => !f.mixedName);
|
|
1540
1758
|
if (specShaped.length > 0) {
|
|
1541
|
-
console.error(
|
|
1759
|
+
console.error(chalk7.bold("\nLikely cause \u2014 spec form-view vocabulary in a standalone form:"));
|
|
1542
1760
|
for (const s of specShaped) {
|
|
1543
|
-
console.error(
|
|
1761
|
+
console.error(chalk7.yellow(
|
|
1544
1762
|
` ${s.path}: { field: '${s.field}' } is the spec form-VIEW shape (an object-field reference).`
|
|
1545
1763
|
));
|
|
1546
1764
|
}
|
|
1547
|
-
console.error(
|
|
1765
|
+
console.error(chalk7.yellow(
|
|
1548
1766
|
` A standalone \`type: 'form'\` component uses { name: \u2026 } (the form data path).
|
|
1549
1767
|
Fix: author the field with \`name\` and its own type/label \u2014 or, to reference object fields
|
|
1550
1768
|
with the spec shape, use an object-bound form (\`type: 'object-form'\` with objectName +
|
|
@@ -1555,61 +1773,28 @@ ${index + 1}. ${issue.message}`));
|
|
|
1555
1773
|
process.exit(1);
|
|
1556
1774
|
}
|
|
1557
1775
|
} catch (error) {
|
|
1558
|
-
console.error(
|
|
1559
|
-
console.error(
|
|
1776
|
+
console.error(chalk7.red("\n\u2717 Error reading or parsing schema file:"));
|
|
1777
|
+
console.error(chalk7.red(error.message));
|
|
1560
1778
|
console.error("");
|
|
1561
1779
|
process.exit(1);
|
|
1562
1780
|
}
|
|
1563
1781
|
}
|
|
1564
1782
|
|
|
1565
|
-
// src/commands/create-plugin.ts
|
|
1566
|
-
import chalk12 from "chalk";
|
|
1567
|
-
import { spawn as spawn2 } from "child_process";
|
|
1568
|
-
import { resolve as resolve5, dirname as dirname3 } from "path";
|
|
1569
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1570
|
-
var __filename = fileURLToPath2(import.meta.url);
|
|
1571
|
-
var __dirname = dirname3(__filename);
|
|
1572
|
-
async function createPlugin(pluginName) {
|
|
1573
|
-
console.log(chalk12.blue("\u{1F680} Creating ObjectUI plugin...\n"));
|
|
1574
|
-
const createPluginScript = resolve5(
|
|
1575
|
-
__dirname,
|
|
1576
|
-
"../../../create-plugin/dist/index.js"
|
|
1577
|
-
);
|
|
1578
|
-
return new Promise((resolve7, reject) => {
|
|
1579
|
-
const child = spawn2("node", [createPluginScript, pluginName], {
|
|
1580
|
-
stdio: "inherit",
|
|
1581
|
-
shell: true
|
|
1582
|
-
});
|
|
1583
|
-
child.on("error", (error) => {
|
|
1584
|
-
console.error(chalk12.red("Failed to create plugin:"), error);
|
|
1585
|
-
reject(error);
|
|
1586
|
-
});
|
|
1587
|
-
child.on("exit", (code) => {
|
|
1588
|
-
if (code === 0) {
|
|
1589
|
-
resolve7();
|
|
1590
|
-
} else {
|
|
1591
|
-
reject(new Error(`create-plugin exited with code ${code}`));
|
|
1592
|
-
}
|
|
1593
|
-
});
|
|
1594
|
-
});
|
|
1595
|
-
}
|
|
1596
|
-
|
|
1597
1783
|
// src/commands/analyze.ts
|
|
1598
|
-
import
|
|
1599
|
-
import { existsSync as
|
|
1600
|
-
import { resolve as
|
|
1784
|
+
import chalk8 from "chalk";
|
|
1785
|
+
import { existsSync as existsSync6, statSync, readdirSync } from "fs";
|
|
1786
|
+
import { resolve as resolve4, join as join7, extname } from "path";
|
|
1601
1787
|
async function analyzeBundleSize() {
|
|
1602
|
-
console.log(
|
|
1603
|
-
const distDir =
|
|
1604
|
-
if (!
|
|
1605
|
-
|
|
1606
|
-
return;
|
|
1788
|
+
console.log(chalk8.bold("\n\u{1F4E6} Bundle Size Analysis\n"));
|
|
1789
|
+
const distDir = resolve4(process.cwd(), "dist");
|
|
1790
|
+
if (!existsSync6(distDir)) {
|
|
1791
|
+
throw new Error("No dist/ directory to analyze. Run `objectui build` first.");
|
|
1607
1792
|
}
|
|
1608
1793
|
const files = [];
|
|
1609
1794
|
function scanDirectory(dir) {
|
|
1610
1795
|
const items = readdirSync(dir);
|
|
1611
1796
|
for (const item of items) {
|
|
1612
|
-
const fullPath =
|
|
1797
|
+
const fullPath = join7(dir, item);
|
|
1613
1798
|
const stat = statSync(fullPath);
|
|
1614
1799
|
if (stat.isDirectory()) {
|
|
1615
1800
|
scanDirectory(fullPath);
|
|
@@ -1628,48 +1813,34 @@ async function analyzeBundleSize() {
|
|
|
1628
1813
|
const cssFiles = files.filter((f) => extname(f.path) === ".css");
|
|
1629
1814
|
const jsSize = jsFiles.reduce((sum, file) => sum + file.size, 0);
|
|
1630
1815
|
const cssSize = cssFiles.reduce((sum, file) => sum + file.size, 0);
|
|
1631
|
-
console.log(
|
|
1632
|
-
console.log(
|
|
1633
|
-
console.log(
|
|
1634
|
-
console.log(
|
|
1635
|
-
console.log(
|
|
1636
|
-
console.log(
|
|
1816
|
+
console.log(chalk8.bold("Summary:"));
|
|
1817
|
+
console.log(chalk8.gray(" Total Size:"), formatBytes(totalSize));
|
|
1818
|
+
console.log(chalk8.gray(" JavaScript:"), formatBytes(jsSize), chalk8.dim(`(${jsFiles.length} files)`));
|
|
1819
|
+
console.log(chalk8.gray(" CSS: "), formatBytes(cssSize), chalk8.dim(`(${cssFiles.length} files)`));
|
|
1820
|
+
console.log(chalk8.gray(" Other: "), formatBytes(totalSize - jsSize - cssSize));
|
|
1821
|
+
console.log(chalk8.bold("\nLargest Files:"));
|
|
1637
1822
|
files.slice(0, 10).forEach((file) => {
|
|
1638
1823
|
const sizeStr = formatBytes(file.size).padStart(10);
|
|
1639
|
-
console.log(
|
|
1824
|
+
console.log(chalk8.gray(` ${sizeStr}`), file.path);
|
|
1640
1825
|
});
|
|
1641
|
-
console.log(
|
|
1826
|
+
console.log(chalk8.bold("\n\u{1F4A1} Recommendations:"));
|
|
1642
1827
|
if (totalSize > 1024 * 1024) {
|
|
1643
|
-
console.log(
|
|
1644
|
-
console.log(
|
|
1828
|
+
console.log(chalk8.yellow(" \u26A0 Total bundle size is large (> 1MB)"));
|
|
1829
|
+
console.log(chalk8.gray(" Consider code splitting or lazy loading"));
|
|
1645
1830
|
}
|
|
1646
1831
|
if (jsSize > 500 * 1024) {
|
|
1647
|
-
console.log(
|
|
1648
|
-
console.log(
|
|
1649
|
-
console.log(
|
|
1650
|
-
console.log(
|
|
1651
|
-
console.log(
|
|
1832
|
+
console.log(chalk8.yellow(" \u26A0 JavaScript bundle is large (> 500KB)"));
|
|
1833
|
+
console.log(chalk8.gray(" Consider:"));
|
|
1834
|
+
console.log(chalk8.gray(" - Tree shaking unused code"));
|
|
1835
|
+
console.log(chalk8.gray(" - Lazy loading components"));
|
|
1836
|
+
console.log(chalk8.gray(" - Using dynamic imports"));
|
|
1652
1837
|
}
|
|
1653
1838
|
if (files.length > 100) {
|
|
1654
|
-
console.log(
|
|
1655
|
-
console.log(
|
|
1839
|
+
console.log(chalk8.yellow(` \u26A0 Large number of files (${files.length})`));
|
|
1840
|
+
console.log(chalk8.gray(" Consider bundling or combining files"));
|
|
1656
1841
|
}
|
|
1657
1842
|
console.log("");
|
|
1658
1843
|
}
|
|
1659
|
-
async function analyzeRenderPerformance() {
|
|
1660
|
-
console.log(chalk13.bold("\n\u26A1 Render Performance Analysis\n"));
|
|
1661
|
-
console.log(chalk13.gray("Performance analysis features:"));
|
|
1662
|
-
console.log(chalk13.gray(" \u2713 Expression caching enabled"));
|
|
1663
|
-
console.log(chalk13.gray(" \u2713 Component memoization available"));
|
|
1664
|
-
console.log(chalk13.gray(" \u2713 Virtual scrolling support for large lists"));
|
|
1665
|
-
console.log(chalk13.bold("\n\u{1F4A1} Performance Tips:"));
|
|
1666
|
-
console.log(chalk13.gray(" \u2022 Use virtual scrolling for lists > 100 items"));
|
|
1667
|
-
console.log(chalk13.gray(" \u2022 Cache frequently evaluated expressions"));
|
|
1668
|
-
console.log(chalk13.gray(" \u2022 Use React.memo for expensive components"));
|
|
1669
|
-
console.log(chalk13.gray(" \u2022 Implement pagination for large datasets"));
|
|
1670
|
-
console.log(chalk13.gray(" \u2022 Use code splitting for large apps"));
|
|
1671
|
-
console.log("");
|
|
1672
|
-
}
|
|
1673
1844
|
function formatBytes(bytes) {
|
|
1674
1845
|
if (bytes === 0) return "0 B";
|
|
1675
1846
|
const k = 1024;
|
|
@@ -1677,26 +1848,20 @@ function formatBytes(bytes) {
|
|
|
1677
1848
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
1678
1849
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
1679
1850
|
}
|
|
1680
|
-
async function analyze(
|
|
1681
|
-
console.log(
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
await analyzeBundleSize();
|
|
1685
|
-
}
|
|
1686
|
-
if (options.renderPerformance || runAll) {
|
|
1687
|
-
await analyzeRenderPerformance();
|
|
1688
|
-
}
|
|
1689
|
-
console.log(chalk13.green("\u2713 Analysis complete!\n"));
|
|
1851
|
+
async function analyze() {
|
|
1852
|
+
console.log(chalk8.blue("\u{1F50D} ObjectUI Performance Analyzer\n"));
|
|
1853
|
+
await analyzeBundleSize();
|
|
1854
|
+
console.log(chalk8.green("\u2713 Analysis complete!\n"));
|
|
1690
1855
|
}
|
|
1691
1856
|
|
|
1692
1857
|
// src/cli.ts
|
|
1693
1858
|
import { readFileSync as readFileSync4 } from "fs";
|
|
1694
|
-
import { fileURLToPath
|
|
1695
|
-
import { dirname as
|
|
1696
|
-
var
|
|
1697
|
-
var
|
|
1859
|
+
import { fileURLToPath } from "url";
|
|
1860
|
+
import { dirname as dirname2, join as join8 } from "path";
|
|
1861
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
1862
|
+
var __dirname = dirname2(__filename);
|
|
1698
1863
|
var packageJson = JSON.parse(
|
|
1699
|
-
readFileSync4(
|
|
1864
|
+
readFileSync4(join8(__dirname, "../package.json"), "utf-8")
|
|
1700
1865
|
);
|
|
1701
1866
|
var program = new Command();
|
|
1702
1867
|
program.name("objectui").description("CLI tool for Object UI - Build applications from JSON schemas").version(packageJson.version);
|
|
@@ -1704,7 +1869,7 @@ program.command("serve").description("Start a development server with your JSON/
|
|
|
1704
1869
|
try {
|
|
1705
1870
|
await serve(schema, options);
|
|
1706
1871
|
} catch (error) {
|
|
1707
|
-
console.error(
|
|
1872
|
+
console.error(chalk9.red("Error:"), error instanceof Error ? error.message : error);
|
|
1708
1873
|
process.exit(1);
|
|
1709
1874
|
}
|
|
1710
1875
|
});
|
|
@@ -1712,7 +1877,7 @@ program.command("dev").description("Start development server (alias for serve)")
|
|
|
1712
1877
|
try {
|
|
1713
1878
|
await dev(schema, options);
|
|
1714
1879
|
} catch (error) {
|
|
1715
|
-
console.error(
|
|
1880
|
+
console.error(chalk9.red("Error:"), error instanceof Error ? error.message : error);
|
|
1716
1881
|
process.exit(1);
|
|
1717
1882
|
}
|
|
1718
1883
|
});
|
|
@@ -1720,7 +1885,7 @@ program.command("build").description("Build application for production").argumen
|
|
|
1720
1885
|
try {
|
|
1721
1886
|
await buildApp(schema, options);
|
|
1722
1887
|
} catch (error) {
|
|
1723
|
-
console.error(
|
|
1888
|
+
console.error(chalk9.red("Error:"), error instanceof Error ? error.message : error);
|
|
1724
1889
|
process.exit(1);
|
|
1725
1890
|
}
|
|
1726
1891
|
});
|
|
@@ -1728,7 +1893,7 @@ program.command("start").description("Start production server").option("-p, --po
|
|
|
1728
1893
|
try {
|
|
1729
1894
|
await start(options);
|
|
1730
1895
|
} catch (error) {
|
|
1731
|
-
console.error(
|
|
1896
|
+
console.error(chalk9.red("Error:"), error instanceof Error ? error.message : error);
|
|
1732
1897
|
process.exit(1);
|
|
1733
1898
|
}
|
|
1734
1899
|
});
|
|
@@ -1736,68 +1901,31 @@ program.command("init").description("Initialize a new Object UI application with
|
|
|
1736
1901
|
try {
|
|
1737
1902
|
await init(name, options);
|
|
1738
1903
|
} catch (error) {
|
|
1739
|
-
console.error(
|
|
1740
|
-
process.exit(1);
|
|
1741
|
-
}
|
|
1742
|
-
});
|
|
1743
|
-
program.command("lint").description("Lint the generated application code").option("--fix", "Automatically fix linting issues").action(async (options) => {
|
|
1744
|
-
try {
|
|
1745
|
-
await lint(options);
|
|
1746
|
-
} catch (error) {
|
|
1747
|
-
console.error(chalk14.red("Error:"), error instanceof Error ? error.message : error);
|
|
1748
|
-
process.exit(1);
|
|
1749
|
-
}
|
|
1750
|
-
});
|
|
1751
|
-
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) => {
|
|
1752
|
-
try {
|
|
1753
|
-
await test(options);
|
|
1754
|
-
} catch (error) {
|
|
1755
|
-
console.error(chalk14.red("Error:"), error instanceof Error ? error.message : error);
|
|
1904
|
+
console.error(chalk9.red("Error:"), error instanceof Error ? error.message : error);
|
|
1756
1905
|
process.exit(1);
|
|
1757
1906
|
}
|
|
1758
1907
|
});
|
|
1759
|
-
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").
|
|
1908
|
+
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) => {
|
|
1760
1909
|
try {
|
|
1761
|
-
if (options.from) {
|
|
1762
|
-
console.log(chalk14.yellow("\n\u26A0 Schema generation from external sources (OpenAPI/Prisma) is not yet implemented."));
|
|
1763
|
-
console.log(chalk14.gray("This feature will be available in a future release.\n"));
|
|
1764
|
-
process.exit(0);
|
|
1765
|
-
}
|
|
1766
1910
|
await generate(type, name);
|
|
1767
1911
|
} catch (error) {
|
|
1768
|
-
console.error(
|
|
1912
|
+
console.error(chalk9.red("Error:"), error instanceof Error ? error.message : error);
|
|
1769
1913
|
process.exit(1);
|
|
1770
1914
|
}
|
|
1771
1915
|
});
|
|
1772
|
-
program.command("doctor").description("Diagnose
|
|
1916
|
+
program.command("doctor").description("Diagnose common project setup issues (reports only, changes nothing)").action(async () => {
|
|
1773
1917
|
try {
|
|
1774
1918
|
await doctor();
|
|
1775
1919
|
} catch (error) {
|
|
1776
|
-
console.error(
|
|
1777
|
-
process.exit(1);
|
|
1778
|
-
}
|
|
1779
|
-
});
|
|
1780
|
-
program.command("add").description("Add a new component renderer to your project").argument("<component>", "Component name (e.g. Input, Grid)").action(async (component) => {
|
|
1781
|
-
try {
|
|
1782
|
-
await add(component);
|
|
1783
|
-
} catch (error) {
|
|
1784
|
-
console.error(chalk14.red("Error:"), error instanceof Error ? error.message : error);
|
|
1920
|
+
console.error(chalk9.red("Error:"), error instanceof Error ? error.message : error);
|
|
1785
1921
|
process.exit(1);
|
|
1786
1922
|
}
|
|
1787
1923
|
});
|
|
1788
|
-
program.command("
|
|
1789
|
-
try {
|
|
1790
|
-
await studio();
|
|
1791
|
-
} catch (error) {
|
|
1792
|
-
console.error(chalk14.red("Error:"), error instanceof Error ? error.message : error);
|
|
1793
|
-
process.exit(1);
|
|
1794
|
-
}
|
|
1795
|
-
});
|
|
1796
|
-
program.command("check").description("Validate schema files").action(async () => {
|
|
1924
|
+
program.command("check").description("Advisory JSON file sweep; run objectui validate for a verdict").action(async () => {
|
|
1797
1925
|
try {
|
|
1798
1926
|
await check();
|
|
1799
1927
|
} catch (error) {
|
|
1800
|
-
console.error(
|
|
1928
|
+
console.error(chalk9.red("Error:"), error instanceof Error ? error.message : error);
|
|
1801
1929
|
process.exit(1);
|
|
1802
1930
|
}
|
|
1803
1931
|
});
|
|
@@ -1805,29 +1933,15 @@ program.command("validate").description("Validate a schema file against ObjectUI
|
|
|
1805
1933
|
try {
|
|
1806
1934
|
await validate(schema);
|
|
1807
1935
|
} catch (error) {
|
|
1808
|
-
console.error(
|
|
1809
|
-
process.exit(1);
|
|
1810
|
-
}
|
|
1811
|
-
});
|
|
1812
|
-
program.command("create").description("Create new resources").argument("<type>", "Type of resource to create (plugin)").argument("<name>", "Name of the resource").action(async (type, name) => {
|
|
1813
|
-
try {
|
|
1814
|
-
if (type === "plugin") {
|
|
1815
|
-
await createPlugin(name);
|
|
1816
|
-
} else {
|
|
1817
|
-
console.error(chalk14.red(`Unknown resource type: ${type}`));
|
|
1818
|
-
console.log(chalk14.gray("Available types: plugin"));
|
|
1819
|
-
process.exit(1);
|
|
1820
|
-
}
|
|
1821
|
-
} catch (error) {
|
|
1822
|
-
console.error(chalk14.red("Error:"), error instanceof Error ? error.message : error);
|
|
1936
|
+
console.error(chalk9.red("Error:"), error instanceof Error ? error.message : error);
|
|
1823
1937
|
process.exit(1);
|
|
1824
1938
|
}
|
|
1825
1939
|
});
|
|
1826
|
-
program.command("analyze").description("Analyze application performance").
|
|
1940
|
+
program.command("analyze").description("Analyze application performance").action(async () => {
|
|
1827
1941
|
try {
|
|
1828
|
-
await analyze(
|
|
1942
|
+
await analyze();
|
|
1829
1943
|
} catch (error) {
|
|
1830
|
-
console.error(
|
|
1944
|
+
console.error(chalk9.red("Error:"), error instanceof Error ? error.message : error);
|
|
1831
1945
|
process.exit(1);
|
|
1832
1946
|
}
|
|
1833
1947
|
});
|