@object-ui/cli 17.3.0 → 17.5.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 +268 -0
- package/README.md +0 -8
- package/dist/{chunk-EV2DCI7W.js → chunk-2MZA766D.js} +429 -551
- package/dist/chunk-2MZA766D.js.map +1 -0
- package/dist/cli.js +225 -94
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +9 -8
- package/dist/chunk-EV2DCI7W.js.map +0 -1
|
@@ -1,16 +1,60 @@
|
|
|
1
1
|
// src/commands/serve.ts
|
|
2
2
|
import { createServer } from "vite";
|
|
3
3
|
import react from "@vitejs/plugin-react";
|
|
4
|
-
import { existsSync as
|
|
5
|
-
import { join as
|
|
4
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
5
|
+
import { join as join3, resolve, relative } from "path";
|
|
6
6
|
import chalk2 from "chalk";
|
|
7
7
|
import { execSync } from "child_process";
|
|
8
8
|
|
|
9
9
|
// src/utils/app-generator.ts
|
|
10
|
-
import { readFileSync, writeFileSync, mkdirSync, readdirSync, statSync, existsSync } from "fs";
|
|
11
|
-
import { join } from "path";
|
|
10
|
+
import { readFileSync as readFileSync2, writeFileSync, mkdirSync, readdirSync, statSync, existsSync as existsSync2 } from "fs";
|
|
11
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
12
12
|
import chalk from "chalk";
|
|
13
13
|
import * as yaml from "js-yaml";
|
|
14
|
+
|
|
15
|
+
// src/utils/scaffold-dependencies.ts
|
|
16
|
+
import { existsSync, readFileSync } from "fs";
|
|
17
|
+
import { dirname, join } from "path";
|
|
18
|
+
import { fileURLToPath } from "url";
|
|
19
|
+
var CLI_PACKAGE_NAME = "@object-ui/cli";
|
|
20
|
+
var cachedCliVersion;
|
|
21
|
+
function cliVersion() {
|
|
22
|
+
if (cachedCliVersion !== void 0) return cachedCliVersion;
|
|
23
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
for (; ; ) {
|
|
25
|
+
const candidate = join(dir, "package.json");
|
|
26
|
+
if (existsSync(candidate)) {
|
|
27
|
+
const manifest = JSON.parse(readFileSync(candidate, "utf-8"));
|
|
28
|
+
if (manifest.name === CLI_PACKAGE_NAME && typeof manifest.version === "string") {
|
|
29
|
+
cachedCliVersion = manifest.version;
|
|
30
|
+
return cachedCliVersion;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const parent = dirname(dir);
|
|
34
|
+
if (parent === dir) break;
|
|
35
|
+
dir = parent;
|
|
36
|
+
}
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Could not locate the ${CLI_PACKAGE_NAME} manifest to version the generated app's platform dependencies against. Refusing to write a package.json with a guessed range.`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
function platformPackageRange() {
|
|
42
|
+
return `^${cliVersion()}`;
|
|
43
|
+
}
|
|
44
|
+
var REACT_RANGE = "19.2.8";
|
|
45
|
+
var SCAFFOLD_DEV_DEPENDENCIES = {
|
|
46
|
+
"@tailwindcss/postcss": "^4.3.3",
|
|
47
|
+
"@types/react": "19.2.18",
|
|
48
|
+
"@types/react-dom": "19.2.4",
|
|
49
|
+
"@vitejs/plugin-react": "^6.0.5",
|
|
50
|
+
autoprefixer: "^10.5.4",
|
|
51
|
+
postcss: "^8.5.26",
|
|
52
|
+
tailwindcss: "^4.3.3",
|
|
53
|
+
typescript: "^6.0.3",
|
|
54
|
+
vite: "^8.2.1"
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// src/utils/app-generator.ts
|
|
14
58
|
function isSupportedSchemaFile(filename) {
|
|
15
59
|
return filename.endsWith(".json") || filename.endsWith(".yml") || filename.endsWith(".yaml");
|
|
16
60
|
}
|
|
@@ -18,7 +62,7 @@ function getBaseFileName(filename) {
|
|
|
18
62
|
return filename.replace(/\.(json|yml|yaml)$/, "");
|
|
19
63
|
}
|
|
20
64
|
function parseSchemaFile(filePath) {
|
|
21
|
-
const content =
|
|
65
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
22
66
|
if (filePath.endsWith(".json")) {
|
|
23
67
|
return JSON.parse(content);
|
|
24
68
|
} else if (filePath.endsWith(".yml") || filePath.endsWith(".yaml")) {
|
|
@@ -31,7 +75,7 @@ function scanPagesDirectory(pagesDir) {
|
|
|
31
75
|
const scanDir = (dir, routePrefix = "") => {
|
|
32
76
|
const entries = readdirSync(dir);
|
|
33
77
|
for (const entry of entries) {
|
|
34
|
-
const fullPath =
|
|
78
|
+
const fullPath = join2(dir, entry);
|
|
35
79
|
const stat = statSync(fullPath);
|
|
36
80
|
if (stat.isDirectory()) {
|
|
37
81
|
const newPrefix = routePrefix + "/" + entry;
|
|
@@ -73,7 +117,255 @@ function scanPagesDirectory(pagesDir) {
|
|
|
73
117
|
});
|
|
74
118
|
return routes;
|
|
75
119
|
}
|
|
120
|
+
var PLATFORM_RUNTIME_PACKAGES = [
|
|
121
|
+
"@object-ui/react",
|
|
122
|
+
"@object-ui/components",
|
|
123
|
+
"@object-ui/plugin-charts",
|
|
124
|
+
"@object-ui/plugin-editor",
|
|
125
|
+
"@object-ui/plugin-kanban",
|
|
126
|
+
"@object-ui/plugin-markdown",
|
|
127
|
+
"@object-ui/plugin-form",
|
|
128
|
+
"@object-ui/plugin-grid",
|
|
129
|
+
"@object-ui/plugin-view"
|
|
130
|
+
];
|
|
131
|
+
function buildAppDependencies() {
|
|
132
|
+
const range = platformPackageRange();
|
|
133
|
+
return {
|
|
134
|
+
react: REACT_RANGE,
|
|
135
|
+
"react-dom": REACT_RANGE,
|
|
136
|
+
...Object.fromEntries(PLATFORM_RUNTIME_PACKAGES.map((name) => [name, range]))
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function buildRoutedAppDependencies() {
|
|
140
|
+
const range = platformPackageRange();
|
|
141
|
+
return {
|
|
142
|
+
react: REACT_RANGE,
|
|
143
|
+
"react-dom": REACT_RANGE,
|
|
144
|
+
"react-router-dom": "^7.18.2",
|
|
145
|
+
"lucide-react": "^1.29.0",
|
|
146
|
+
...Object.fromEntries(PLATFORM_RUNTIME_PACKAGES.map((name) => [name, range]))
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
var APP_VITE_ENV_D_TS = `/// <reference types="vite/client" />
|
|
150
|
+
`;
|
|
151
|
+
var APP_TSCONFIG = {
|
|
152
|
+
compilerOptions: {
|
|
153
|
+
target: "ES2020",
|
|
154
|
+
useDefineForClassFields: true,
|
|
155
|
+
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
156
|
+
module: "ESNext",
|
|
157
|
+
skipLibCheck: true,
|
|
158
|
+
moduleResolution: "bundler",
|
|
159
|
+
allowImportingTsExtensions: true,
|
|
160
|
+
resolveJsonModule: true,
|
|
161
|
+
isolatedModules: true,
|
|
162
|
+
noEmit: true,
|
|
163
|
+
jsx: "react-jsx",
|
|
164
|
+
strict: true,
|
|
165
|
+
noUnusedLocals: true,
|
|
166
|
+
noUnusedParameters: true,
|
|
167
|
+
noFallthroughCasesInSwitch: true
|
|
168
|
+
},
|
|
169
|
+
include: ["src"]
|
|
170
|
+
};
|
|
171
|
+
var APP_POSTCSS_CONFIG = `export default {
|
|
172
|
+
plugins: {
|
|
173
|
+
'@tailwindcss/postcss': {},
|
|
174
|
+
autoprefixer: {},
|
|
175
|
+
},
|
|
176
|
+
};`;
|
|
177
|
+
function currentContext() {
|
|
178
|
+
const cwd = process.cwd();
|
|
179
|
+
return { cwd, isMonorepo: existsSync2(join2(cwd, "pnpm-workspace.yaml")) };
|
|
180
|
+
}
|
|
181
|
+
function buildAppPackageJson(context) {
|
|
182
|
+
return {
|
|
183
|
+
name: "objectui-temp-app",
|
|
184
|
+
private: true,
|
|
185
|
+
type: "module",
|
|
186
|
+
// In monorepo, we use root node_modules, so we don't need dependencies here
|
|
187
|
+
dependencies: context.isMonorepo ? {} : buildAppDependencies(),
|
|
188
|
+
devDependencies: context.isMonorepo ? {} : { ...SCAFFOLD_DEV_DEPENDENCIES }
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function buildRoutedAppPackageJson() {
|
|
192
|
+
return {
|
|
193
|
+
name: "objectui-temp-app",
|
|
194
|
+
private: true,
|
|
195
|
+
type: "module",
|
|
196
|
+
dependencies: buildRoutedAppDependencies(),
|
|
197
|
+
devDependencies: { ...SCAFFOLD_DEV_DEPENDENCIES }
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function buildAppSourceDirectives(context) {
|
|
201
|
+
const sources = [`@source '../index.html';`, `@source '../src/**/*.{js,ts,jsx,tsx,json}';`];
|
|
202
|
+
if (context.isMonorepo) {
|
|
203
|
+
sources.push(`@source '${join2(context.cwd, "packages/components/src/**/*.{ts,tsx}")}';`);
|
|
204
|
+
sources.push(`@source '${join2(context.cwd, "packages/plugin-*/src/**/*.{ts,tsx}")}';`);
|
|
205
|
+
} else {
|
|
206
|
+
sources.push(`@source '../node_modules/@object-ui/*/dist/**/*.js';`);
|
|
207
|
+
}
|
|
208
|
+
return sources;
|
|
209
|
+
}
|
|
210
|
+
var APP_THEME_TOKENS = `@theme {
|
|
211
|
+
/* Border radius tokens */
|
|
212
|
+
--radius-lg: var(--radius);
|
|
213
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
214
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
215
|
+
|
|
216
|
+
/* Color tokens mapped to the CSS variables declared below */
|
|
217
|
+
--color-border: hsl(var(--border));
|
|
218
|
+
--color-input: hsl(var(--input));
|
|
219
|
+
--color-ring: hsl(var(--ring));
|
|
220
|
+
--color-background: hsl(var(--background));
|
|
221
|
+
--color-foreground: hsl(var(--foreground));
|
|
222
|
+
--color-primary: hsl(var(--primary));
|
|
223
|
+
--color-primary-foreground: hsl(var(--primary-foreground));
|
|
224
|
+
--color-secondary: hsl(var(--secondary));
|
|
225
|
+
--color-secondary-foreground: hsl(var(--secondary-foreground));
|
|
226
|
+
--color-destructive: hsl(var(--destructive));
|
|
227
|
+
--color-destructive-foreground: hsl(var(--destructive-foreground));
|
|
228
|
+
--color-muted: hsl(var(--muted));
|
|
229
|
+
--color-muted-foreground: hsl(var(--muted-foreground));
|
|
230
|
+
--color-accent: hsl(var(--accent));
|
|
231
|
+
--color-accent-foreground: hsl(var(--accent-foreground));
|
|
232
|
+
--color-popover: hsl(var(--popover));
|
|
233
|
+
--color-popover-foreground: hsl(var(--popover-foreground));
|
|
234
|
+
--color-card: hsl(var(--card));
|
|
235
|
+
--color-card-foreground: hsl(var(--card-foreground));
|
|
236
|
+
--color-sidebar: hsl(var(--sidebar));
|
|
237
|
+
--color-sidebar-foreground: hsl(var(--sidebar-foreground));
|
|
238
|
+
--color-sidebar-primary: hsl(var(--sidebar-primary));
|
|
239
|
+
--color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));
|
|
240
|
+
--color-sidebar-accent: hsl(var(--sidebar-accent));
|
|
241
|
+
--color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));
|
|
242
|
+
--color-sidebar-border: hsl(var(--sidebar-border));
|
|
243
|
+
--color-sidebar-ring: hsl(var(--sidebar-ring));
|
|
244
|
+
|
|
245
|
+
/* Chart colors */
|
|
246
|
+
--color-chart-1: hsl(var(--chart-1));
|
|
247
|
+
--color-chart-2: hsl(var(--chart-2));
|
|
248
|
+
--color-chart-3: hsl(var(--chart-3));
|
|
249
|
+
--color-chart-4: hsl(var(--chart-4));
|
|
250
|
+
--color-chart-5: hsl(var(--chart-5));
|
|
251
|
+
}`;
|
|
252
|
+
var APP_THEME_VARIABLES = `:root {
|
|
253
|
+
color-scheme: light;
|
|
254
|
+
|
|
255
|
+
--background: 0 0% 100%;
|
|
256
|
+
--foreground: 222.2 84% 4.9%;
|
|
257
|
+
--card: 0 0% 100%;
|
|
258
|
+
--card-foreground: 222.2 84% 4.9%;
|
|
259
|
+
--popover: 0 0% 100%;
|
|
260
|
+
--popover-foreground: 222.2 84% 4.9%;
|
|
261
|
+
--primary: 222.2 47.4% 11.2%;
|
|
262
|
+
--primary-foreground: 210 40% 98%;
|
|
263
|
+
--secondary: 210 40% 96.1%;
|
|
264
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
265
|
+
--muted: 210 40% 96.1%;
|
|
266
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
267
|
+
--accent: 210 40% 96.1%;
|
|
268
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
|
269
|
+
--destructive: 0 84.2% 60.2%;
|
|
270
|
+
--destructive-foreground: 210 40% 98%;
|
|
271
|
+
--border: 214.3 31.8% 91.4%;
|
|
272
|
+
--input: 214.3 31.8% 91.4%;
|
|
273
|
+
--ring: 222.2 84% 4.9%;
|
|
274
|
+
--radius: 0.5rem;
|
|
275
|
+
--chart-1: 12 76% 61%;
|
|
276
|
+
--chart-2: 173 58% 39%;
|
|
277
|
+
--chart-3: 197 37% 24%;
|
|
278
|
+
--chart-4: 43 74% 66%;
|
|
279
|
+
--chart-5: 27 87% 67%;
|
|
280
|
+
|
|
281
|
+
/* Sidebar colors */
|
|
282
|
+
--sidebar: 0 0% 98%;
|
|
283
|
+
--sidebar-foreground: 240 5.3% 26.1%;
|
|
284
|
+
--sidebar-primary: 240 5.9% 10%;
|
|
285
|
+
--sidebar-primary-foreground: 0 0% 98%;
|
|
286
|
+
--sidebar-accent: 240 4.8% 95.9%;
|
|
287
|
+
--sidebar-accent-foreground: 240 5.9% 10%;
|
|
288
|
+
--sidebar-border: 220 13% 91%;
|
|
289
|
+
--sidebar-ring: 217.2 91.2% 59.8%;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.dark {
|
|
293
|
+
color-scheme: dark;
|
|
294
|
+
|
|
295
|
+
--background: 222.2 84% 4.9%;
|
|
296
|
+
--foreground: 210 40% 98%;
|
|
297
|
+
--card: 222.2 84% 4.9%;
|
|
298
|
+
--card-foreground: 210 40% 98%;
|
|
299
|
+
--popover: 222.2 84% 4.9%;
|
|
300
|
+
--popover-foreground: 210 40% 98%;
|
|
301
|
+
--primary: 210 40% 98%;
|
|
302
|
+
--primary-foreground: 222.2 47.4% 11.2%;
|
|
303
|
+
--secondary: 217.2 32.6% 17.5%;
|
|
304
|
+
--secondary-foreground: 210 40% 98%;
|
|
305
|
+
--muted: 217.2 32.6% 17.5%;
|
|
306
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
307
|
+
--accent: 217.2 32.6% 17.5%;
|
|
308
|
+
--accent-foreground: 210 40% 98%;
|
|
309
|
+
--destructive: 0 62.8% 30.6%;
|
|
310
|
+
--destructive-foreground: 210 40% 98%;
|
|
311
|
+
--border: 217.2 32.6% 17.5%;
|
|
312
|
+
--input: 217.2 32.6% 17.5%;
|
|
313
|
+
--ring: 212.7 26.8% 83.9%;
|
|
314
|
+
--chart-1: 220 70% 50%;
|
|
315
|
+
--chart-2: 160 60% 45%;
|
|
316
|
+
--chart-3: 30 80% 55%;
|
|
317
|
+
--chart-4: 280 65% 60%;
|
|
318
|
+
--chart-5: 340 75% 55%;
|
|
319
|
+
|
|
320
|
+
/* Sidebar colors for dark mode */
|
|
321
|
+
--sidebar: 240 5.9% 10%;
|
|
322
|
+
--sidebar-foreground: 240 4.8% 95.9%;
|
|
323
|
+
--sidebar-primary: 224.3 76.3% 48%;
|
|
324
|
+
--sidebar-primary-foreground: 0 0% 100%;
|
|
325
|
+
--sidebar-accent: 240 3.7% 15.9%;
|
|
326
|
+
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
|
327
|
+
--sidebar-border: 240 3.7% 15.9%;
|
|
328
|
+
--sidebar-ring: 217.2 91.2% 59.8%;
|
|
329
|
+
}`;
|
|
330
|
+
function buildAppIndexCss(context) {
|
|
331
|
+
return `@import 'tailwindcss';
|
|
332
|
+
|
|
333
|
+
/* Class-based dark variant: follow \`.dark\` on <html> \u2014 the routed app's
|
|
334
|
+
\`src/theme-provider.tsx\` toggles exactly that class \u2014 instead of the OS
|
|
335
|
+
\`prefers-color-scheme\`. Same spelling as packages/components/src/index.css. */
|
|
336
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
337
|
+
|
|
338
|
+
/* Sources to scan for utility classes (v4's replacement for v3 \`content\`) */
|
|
339
|
+
${buildAppSourceDirectives(context).join("\n")}
|
|
340
|
+
|
|
341
|
+
${APP_THEME_TOKENS}
|
|
342
|
+
|
|
343
|
+
${APP_THEME_VARIABLES}
|
|
344
|
+
|
|
345
|
+
* {
|
|
346
|
+
border-color: hsl(var(--border));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
body {
|
|
350
|
+
background-color: hsl(var(--background));
|
|
351
|
+
color: hsl(var(--foreground));
|
|
352
|
+
font-family: var(--font-sans);
|
|
353
|
+
-webkit-font-smoothing: antialiased;
|
|
354
|
+
-moz-osx-font-smoothing: grayscale;
|
|
355
|
+
min-height: 100vh;
|
|
356
|
+
}`;
|
|
357
|
+
}
|
|
358
|
+
function writeGeneratedFiles(tmpDir, files) {
|
|
359
|
+
for (const [relativePath, contents] of Object.entries(files)) {
|
|
360
|
+
const target = join2(tmpDir, relativePath);
|
|
361
|
+
mkdirSync(dirname2(target), { recursive: true });
|
|
362
|
+
writeFileSync(target, contents);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
76
365
|
function createTempApp(tmpDir, schema) {
|
|
366
|
+
writeGeneratedFiles(tmpDir, buildAppFiles(schema, currentContext()));
|
|
367
|
+
}
|
|
368
|
+
function buildAppFiles(schema, context) {
|
|
77
369
|
const html = `<!DOCTYPE html>
|
|
78
370
|
<html lang="en">
|
|
79
371
|
<head>
|
|
@@ -86,9 +378,6 @@ function createTempApp(tmpDir, schema) {
|
|
|
86
378
|
<script type="module" src="/src/main.tsx"></script>
|
|
87
379
|
</body>
|
|
88
380
|
</html>`;
|
|
89
|
-
writeFileSync(join(tmpDir, "index.html"), html);
|
|
90
|
-
const srcDir = join(tmpDir, "src");
|
|
91
|
-
mkdirSync(srcDir, { recursive: true });
|
|
92
381
|
const mainTsx = `import React from 'react';
|
|
93
382
|
import ReactDOM from 'react-dom/client';
|
|
94
383
|
import App from './App';
|
|
@@ -99,7 +388,6 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
99
388
|
<App />
|
|
100
389
|
</React.StrictMode>
|
|
101
390
|
);`;
|
|
102
|
-
writeFileSync(join(srcDir, "main.tsx"), mainTsx);
|
|
103
391
|
const appTsx = `import { SchemaRenderer } from '@object-ui/react';
|
|
104
392
|
import '@object-ui/components';
|
|
105
393
|
import '@object-ui/plugin-charts';
|
|
@@ -117,256 +405,22 @@ function App() {
|
|
|
117
405
|
}
|
|
118
406
|
|
|
119
407
|
export default App;`;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
--card: 0 0% 100%;
|
|
130
|
-
--card-foreground: 222.2 84% 4.9%;
|
|
131
|
-
--popover: 0 0% 100%;
|
|
132
|
-
--popover-foreground: 222.2 84% 4.9%;
|
|
133
|
-
--primary: 222.2 47.4% 11.2%;
|
|
134
|
-
--primary-foreground: 210 40% 98%;
|
|
135
|
-
--secondary: 210 40% 96.1%;
|
|
136
|
-
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
137
|
-
--muted: 210 40% 96.1%;
|
|
138
|
-
--muted-foreground: 215.4 16.3% 46.9%;
|
|
139
|
-
--accent: 210 40% 96.1%;
|
|
140
|
-
--accent-foreground: 222.2 47.4% 11.2%;
|
|
141
|
-
--destructive: 0 84.2% 60.2%;
|
|
142
|
-
--destructive-foreground: 210 40% 98%;
|
|
143
|
-
--border: 214.3 31.8% 91.4%;
|
|
144
|
-
--input: 214.3 31.8% 91.4%;
|
|
145
|
-
--ring: 222.2 84% 4.9%;
|
|
146
|
-
--radius: 0.5rem;
|
|
147
|
-
--chart-1: 12 76% 61%;
|
|
148
|
-
--chart-2: 173 58% 39%;
|
|
149
|
-
--chart-3: 197 37% 24%;
|
|
150
|
-
--chart-4: 43 74% 66%;
|
|
151
|
-
--chart-5: 27 87% 67%;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.dark {
|
|
155
|
-
--background: 222.2 84% 4.9%;
|
|
156
|
-
--foreground: 210 40% 98%;
|
|
157
|
-
--card: 222.2 84% 4.9%;
|
|
158
|
-
--card-foreground: 210 40% 98%;
|
|
159
|
-
--popover: 222.2 84% 4.9%;
|
|
160
|
-
--popover-foreground: 210 40% 98%;
|
|
161
|
-
--primary: 210 40% 98%;
|
|
162
|
-
--primary-foreground: 222.2 47.4% 11.2%;
|
|
163
|
-
--secondary: 217.2 32.6% 17.5%;
|
|
164
|
-
--secondary-foreground: 210 40% 98%;
|
|
165
|
-
--muted: 217.2 32.6% 17.5%;
|
|
166
|
-
--muted-foreground: 215 20.2% 65.1%;
|
|
167
|
-
--accent: 217.2 32.6% 17.5%;
|
|
168
|
-
--accent-foreground: 210 40% 98%;
|
|
169
|
-
--destructive: 0 62.8% 30.6%;
|
|
170
|
-
--destructive-foreground: 210 40% 98%;
|
|
171
|
-
--border: 217.2 32.6% 17.5%;
|
|
172
|
-
--input: 217.2 32.6% 17.5%;
|
|
173
|
-
--ring: 212.7 26.8% 83.9%;
|
|
174
|
-
--chart-1: 220 70% 50%;
|
|
175
|
-
--chart-2: 160 60% 45%;
|
|
176
|
-
--chart-3: 30 80% 55%;
|
|
177
|
-
--chart-4: 280 65% 60%;
|
|
178
|
-
--chart-5: 340 75% 55%;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
@layer base {
|
|
183
|
-
* {
|
|
184
|
-
@apply border-border;
|
|
185
|
-
}
|
|
186
|
-
body {
|
|
187
|
-
@apply bg-background text-foreground;
|
|
188
|
-
}
|
|
189
|
-
}`;
|
|
190
|
-
writeFileSync(join(srcDir, "index.css"), indexCss);
|
|
191
|
-
const tailwindConfig = `/** @type {import('tailwindcss').Config} */
|
|
192
|
-
export default {
|
|
193
|
-
darkMode: ['class'],
|
|
194
|
-
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
|
195
|
-
theme: {
|
|
196
|
-
extend: {
|
|
197
|
-
borderRadius: {
|
|
198
|
-
lg: 'var(--radius)',
|
|
199
|
-
md: 'calc(var(--radius) - 2px)',
|
|
200
|
-
sm: 'calc(var(--radius) - 4px)',
|
|
201
|
-
},
|
|
202
|
-
colors: {
|
|
203
|
-
background: 'hsl(var(--background))',
|
|
204
|
-
foreground: 'hsl(var(--foreground))',
|
|
205
|
-
card: {
|
|
206
|
-
DEFAULT: 'hsl(var(--card))',
|
|
207
|
-
foreground: 'hsl(var(--card-foreground))',
|
|
208
|
-
},
|
|
209
|
-
popover: {
|
|
210
|
-
DEFAULT: 'hsl(var(--popover))',
|
|
211
|
-
foreground: 'hsl(var(--popover-foreground))',
|
|
212
|
-
},
|
|
213
|
-
primary: {
|
|
214
|
-
DEFAULT: 'hsl(var(--primary))',
|
|
215
|
-
foreground: 'hsl(var(--primary-foreground))',
|
|
216
|
-
},
|
|
217
|
-
secondary: {
|
|
218
|
-
DEFAULT: 'hsl(var(--secondary))',
|
|
219
|
-
foreground: 'hsl(var(--secondary-foreground))',
|
|
220
|
-
},
|
|
221
|
-
muted: {
|
|
222
|
-
DEFAULT: 'hsl(var(--muted))',
|
|
223
|
-
foreground: 'hsl(var(--muted-foreground))',
|
|
224
|
-
},
|
|
225
|
-
accent: {
|
|
226
|
-
DEFAULT: 'hsl(var(--accent))',
|
|
227
|
-
foreground: 'hsl(var(--accent-foreground))',
|
|
228
|
-
},
|
|
229
|
-
destructive: {
|
|
230
|
-
DEFAULT: 'hsl(var(--destructive))',
|
|
231
|
-
foreground: 'hsl(var(--destructive-foreground))',
|
|
232
|
-
},
|
|
233
|
-
border: 'hsl(var(--border))',
|
|
234
|
-
input: 'hsl(var(--input))',
|
|
235
|
-
ring: 'hsl(var(--ring))',
|
|
236
|
-
chart: {
|
|
237
|
-
1: 'hsl(var(--chart-1))',
|
|
238
|
-
2: 'hsl(var(--chart-2))',
|
|
239
|
-
3: 'hsl(var(--chart-3))',
|
|
240
|
-
4: 'hsl(var(--chart-4))',
|
|
241
|
-
5: 'hsl(var(--chart-5))',
|
|
242
|
-
},
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
},
|
|
246
|
-
plugins: [],
|
|
247
|
-
};`;
|
|
248
|
-
const cwd = process.cwd();
|
|
249
|
-
const isMonorepo = existsSync(join(cwd, "pnpm-workspace.yaml"));
|
|
250
|
-
const contentPaths = ["'./index.html'", "'./src/**/*.{js,ts,jsx,tsx,json}'"];
|
|
251
|
-
if (isMonorepo) {
|
|
252
|
-
const componentsPath = join(cwd, "packages/components/src/**/*.{ts,tsx}");
|
|
253
|
-
const pluginsPath = join(cwd, "packages/plugin-*/src/**/*.{ts,tsx}");
|
|
254
|
-
contentPaths.push(`'${componentsPath}'`);
|
|
255
|
-
contentPaths.push(`'${pluginsPath}'`);
|
|
256
|
-
}
|
|
257
|
-
const finalTailwindConfig = `/** @type {import('tailwindcss').Config} */
|
|
258
|
-
export default {
|
|
259
|
-
darkMode: ['class'],
|
|
260
|
-
content: [${contentPaths.join(", ")}],
|
|
261
|
-
theme: {
|
|
262
|
-
extend: {
|
|
263
|
-
borderRadius: {
|
|
264
|
-
lg: 'var(--radius)',
|
|
265
|
-
md: 'calc(var(--radius) - 2px)',
|
|
266
|
-
sm: 'calc(var(--radius) - 4px)',
|
|
267
|
-
},
|
|
268
|
-
colors: {
|
|
269
|
-
background: 'hsl(var(--background))',
|
|
270
|
-
foreground: 'hsl(var(--foreground))',
|
|
271
|
-
card: {
|
|
272
|
-
DEFAULT: 'hsl(var(--card))',
|
|
273
|
-
foreground: 'hsl(var(--card-foreground))',
|
|
274
|
-
},
|
|
275
|
-
popover: {
|
|
276
|
-
DEFAULT: 'hsl(var(--popover))',
|
|
277
|
-
foreground: 'hsl(var(--popover-foreground))',
|
|
278
|
-
},
|
|
279
|
-
primary: {
|
|
280
|
-
DEFAULT: 'hsl(var(--primary))',
|
|
281
|
-
foreground: 'hsl(var(--primary-foreground))',
|
|
282
|
-
},
|
|
283
|
-
secondary: {
|
|
284
|
-
DEFAULT: 'hsl(var(--secondary))',
|
|
285
|
-
foreground: 'hsl(var(--secondary-foreground))',
|
|
286
|
-
},
|
|
287
|
-
muted: {
|
|
288
|
-
DEFAULT: 'hsl(var(--muted))',
|
|
289
|
-
foreground: 'hsl(var(--muted-foreground))',
|
|
290
|
-
},
|
|
291
|
-
accent: {
|
|
292
|
-
DEFAULT: 'hsl(var(--accent))',
|
|
293
|
-
foreground: 'hsl(var(--accent-foreground))',
|
|
294
|
-
},
|
|
295
|
-
destructive: {
|
|
296
|
-
DEFAULT: 'hsl(var(--destructive))',
|
|
297
|
-
foreground: 'hsl(var(--destructive-foreground))',
|
|
298
|
-
},
|
|
299
|
-
border: 'hsl(var(--border))',
|
|
300
|
-
input: 'hsl(var(--input))',
|
|
301
|
-
ring: 'hsl(var(--ring))',
|
|
302
|
-
chart: {
|
|
303
|
-
1: 'hsl(var(--chart-1))',
|
|
304
|
-
2: 'hsl(var(--chart-2))',
|
|
305
|
-
3: 'hsl(var(--chart-3))',
|
|
306
|
-
4: 'hsl(var(--chart-4))',
|
|
307
|
-
5: 'hsl(var(--chart-5))',
|
|
308
|
-
},
|
|
309
|
-
},
|
|
310
|
-
},
|
|
311
|
-
},
|
|
312
|
-
plugins: [],
|
|
313
|
-
};`;
|
|
314
|
-
writeFileSync(join(tmpDir, "tailwind.config.js"), finalTailwindConfig);
|
|
315
|
-
const finalPostcssConfig = `export default {
|
|
316
|
-
plugins: {
|
|
317
|
-
tailwindcss: {},
|
|
318
|
-
autoprefixer: {},
|
|
319
|
-
},
|
|
320
|
-
};`;
|
|
321
|
-
writeFileSync(join(tmpDir, "postcss.config.js"), finalPostcssConfig);
|
|
322
|
-
const baseDependencies = {
|
|
323
|
-
react: "^18.3.1",
|
|
324
|
-
"react-dom": "^18.3.1",
|
|
325
|
-
"@object-ui/react": "^0.1.0",
|
|
326
|
-
"@object-ui/components": "^0.1.0"
|
|
327
|
-
};
|
|
328
|
-
const baseDevDependencies = {
|
|
329
|
-
"@types/react": "^18.3.12",
|
|
330
|
-
"@types/react-dom": "^18.3.1",
|
|
331
|
-
"@vitejs/plugin-react": "^4.2.1",
|
|
332
|
-
autoprefixer: "^10.4.23",
|
|
333
|
-
postcss: "^8.5.6",
|
|
334
|
-
tailwindcss: "^3.4.19",
|
|
335
|
-
typescript: "~5.7.3",
|
|
336
|
-
vite: "^5.0.0"
|
|
337
|
-
};
|
|
338
|
-
const packageJson = {
|
|
339
|
-
name: "objectui-temp-app",
|
|
340
|
-
private: true,
|
|
341
|
-
type: "module",
|
|
342
|
-
// In monorepo, we use root node_modules, so we don't need dependencies here
|
|
343
|
-
dependencies: isMonorepo ? {} : baseDependencies,
|
|
344
|
-
devDependencies: isMonorepo ? {} : baseDevDependencies
|
|
345
|
-
};
|
|
346
|
-
writeFileSync(join(tmpDir, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
347
|
-
const tsconfig = {
|
|
348
|
-
compilerOptions: {
|
|
349
|
-
target: "ES2020",
|
|
350
|
-
useDefineForClassFields: true,
|
|
351
|
-
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
352
|
-
module: "ESNext",
|
|
353
|
-
skipLibCheck: true,
|
|
354
|
-
moduleResolution: "bundler",
|
|
355
|
-
allowImportingTsExtensions: true,
|
|
356
|
-
resolveJsonModule: true,
|
|
357
|
-
isolatedModules: true,
|
|
358
|
-
noEmit: true,
|
|
359
|
-
jsx: "react-jsx",
|
|
360
|
-
strict: true,
|
|
361
|
-
noUnusedLocals: true,
|
|
362
|
-
noUnusedParameters: true,
|
|
363
|
-
noFallthroughCasesInSwitch: true
|
|
364
|
-
},
|
|
365
|
-
include: ["src"]
|
|
408
|
+
return {
|
|
409
|
+
"index.html": html,
|
|
410
|
+
"src/main.tsx": mainTsx,
|
|
411
|
+
"src/App.tsx": appTsx,
|
|
412
|
+
"src/vite-env.d.ts": APP_VITE_ENV_D_TS,
|
|
413
|
+
"src/index.css": buildAppIndexCss(context),
|
|
414
|
+
"postcss.config.js": APP_POSTCSS_CONFIG,
|
|
415
|
+
"package.json": JSON.stringify(buildAppPackageJson(context), null, 2),
|
|
416
|
+
"tsconfig.json": JSON.stringify(APP_TSCONFIG, null, 2)
|
|
366
417
|
};
|
|
367
|
-
writeFileSync(join(tmpDir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
|
|
368
418
|
}
|
|
369
419
|
function createTempAppWithRouting(tmpDir, routes, appConfig) {
|
|
420
|
+
writeGeneratedFiles(tmpDir, buildRoutedAppFiles(routes, appConfig, currentContext()));
|
|
421
|
+
}
|
|
422
|
+
function buildRoutedAppFiles(routes, appConfig, context) {
|
|
423
|
+
const files = {};
|
|
370
424
|
const html = `<!DOCTYPE html>
|
|
371
425
|
<html lang="en">
|
|
372
426
|
<head>
|
|
@@ -379,20 +433,13 @@ function createTempAppWithRouting(tmpDir, routes, appConfig) {
|
|
|
379
433
|
<script type="module" src="/src/main.tsx"></script>
|
|
380
434
|
</body>
|
|
381
435
|
</html>`;
|
|
382
|
-
|
|
383
|
-
const srcDir = join(tmpDir, "src");
|
|
384
|
-
mkdirSync(srcDir, { recursive: true });
|
|
385
|
-
const schemasDir = join(srcDir, "schemas");
|
|
386
|
-
mkdirSync(schemasDir, { recursive: true });
|
|
436
|
+
files["index.html"] = html;
|
|
387
437
|
const schemaImports = [];
|
|
388
438
|
const routeComponents = [];
|
|
389
439
|
routes.forEach((route, index) => {
|
|
390
440
|
const schemaVarName = `schema${index}`;
|
|
391
441
|
const schemaFileName = `page${index}.json`;
|
|
392
|
-
|
|
393
|
-
join(schemasDir, schemaFileName),
|
|
394
|
-
JSON.stringify(route.schema, null, 2)
|
|
395
|
-
);
|
|
442
|
+
files[`src/schemas/${schemaFileName}`] = JSON.stringify(route.schema, null, 2);
|
|
396
443
|
schemaImports.push(`import ${schemaVarName} from './schemas/${schemaFileName}';`);
|
|
397
444
|
routeComponents.push(` <Route path="${route.path}" element={<SchemaRenderer schema={${schemaVarName}} />} />`);
|
|
398
445
|
});
|
|
@@ -469,7 +516,7 @@ export const useTheme = () => {
|
|
|
469
516
|
|
|
470
517
|
return context
|
|
471
518
|
}`;
|
|
472
|
-
|
|
519
|
+
files["src/theme-provider.tsx"] = themeProviderTsx;
|
|
473
520
|
const mainTsx = `import React from 'react';
|
|
474
521
|
import ReactDOM from 'react-dom/client';
|
|
475
522
|
import App from './App';
|
|
@@ -483,19 +530,18 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
483
530
|
</ThemeProvider>
|
|
484
531
|
</React.StrictMode>
|
|
485
532
|
);`;
|
|
486
|
-
|
|
533
|
+
files["src/main.tsx"] = mainTsx;
|
|
487
534
|
let layoutImport = "";
|
|
488
535
|
let layoutWrapperStart = "";
|
|
489
536
|
let layoutWrapperEnd = "";
|
|
490
537
|
if (appConfig) {
|
|
491
538
|
const layoutCode = `
|
|
539
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
492
540
|
import { Link, useLocation } from 'react-router-dom';
|
|
493
541
|
import * as LucideIcons from 'lucide-react';
|
|
494
542
|
import { Moon, Sun } from "lucide-react"
|
|
495
543
|
import { useTheme } from "./theme-provider"
|
|
496
|
-
import {
|
|
497
|
-
cn,
|
|
498
|
-
Button,
|
|
544
|
+
import {
|
|
499
545
|
DropdownMenu,
|
|
500
546
|
DropdownMenuContent,
|
|
501
547
|
DropdownMenuItem,
|
|
@@ -507,8 +553,6 @@ import {
|
|
|
507
553
|
SidebarHeader,
|
|
508
554
|
SidebarRail,
|
|
509
555
|
SidebarGroup,
|
|
510
|
-
SidebarGroupContent,
|
|
511
|
-
SidebarGroupLabel,
|
|
512
556
|
SidebarMenu,
|
|
513
557
|
SidebarMenuItem,
|
|
514
558
|
SidebarMenuButton,
|
|
@@ -521,11 +565,36 @@ import {
|
|
|
521
565
|
Collapsible,
|
|
522
566
|
CollapsibleTrigger,
|
|
523
567
|
CollapsibleContent
|
|
524
|
-
} from '@object-ui/components';
|
|
568
|
+
} from '@object-ui/components';
|
|
569
|
+
|
|
570
|
+
/** One entry of \`app.json\`'s \`menu\`, as this layout reads it. */
|
|
571
|
+
type MenuItem = {
|
|
572
|
+
label?: string;
|
|
573
|
+
path?: string;
|
|
574
|
+
icon?: string;
|
|
575
|
+
children?: MenuItem[];
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
/** The \`app.json\` fields this layout renders. */
|
|
579
|
+
type AppConfig = {
|
|
580
|
+
title?: string;
|
|
581
|
+
logo?: string;
|
|
582
|
+
menu?: MenuItem[];
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
// Lucide publishes every icon as a named export, and a menu entry names one as
|
|
586
|
+
// a string \u2014 so the lookup is a runtime index into the namespace object, which
|
|
587
|
+
// has no index signature. Narrowing it to the component-by-name shape this file
|
|
588
|
+
// actually uses keeps that honest without an \`any\` or a \`@ts-expect-error\`; the
|
|
589
|
+
// \`undefined\` arm is real, since the namespace also exports helpers that are not
|
|
590
|
+
// components and a schema may name an icon that does not exist.
|
|
591
|
+
const lucideIcons = LucideIcons as unknown as Record<
|
|
592
|
+
string,
|
|
593
|
+
ComponentType<{ className?: string }> | undefined
|
|
594
|
+
>;
|
|
525
595
|
|
|
526
|
-
const DynamicIcon = ({ name, className }) => {
|
|
527
|
-
|
|
528
|
-
const Icon = LucideIcons[name];
|
|
596
|
+
const DynamicIcon = ({ name, className }: { name: string; className?: string }) => {
|
|
597
|
+
const Icon = lucideIcons[name];
|
|
529
598
|
if (!Icon) return null;
|
|
530
599
|
return <Icon className={className} />;
|
|
531
600
|
};
|
|
@@ -566,7 +635,7 @@ export function ModeToggle() {
|
|
|
566
635
|
)
|
|
567
636
|
}
|
|
568
637
|
|
|
569
|
-
const AppLayout = ({ app, children }) => {
|
|
638
|
+
const AppLayout = ({ app, children }: { app: AppConfig; children: ReactNode }) => {
|
|
570
639
|
const location = useLocation();
|
|
571
640
|
const menu = app.menu || [];
|
|
572
641
|
|
|
@@ -668,13 +737,13 @@ const AppLayout = ({ app, children }) => {
|
|
|
668
737
|
|
|
669
738
|
export default AppLayout;
|
|
670
739
|
`;
|
|
671
|
-
|
|
740
|
+
files["src/Layout.tsx"] = layoutCode;
|
|
672
741
|
layoutImport = `import AppLayout from './Layout';
|
|
673
742
|
const appConfig = ${JSON.stringify(appConfig)};`;
|
|
674
743
|
layoutWrapperStart = `<AppLayout app={appConfig}>`;
|
|
675
744
|
layoutWrapperEnd = `</AppLayout>`;
|
|
676
745
|
}
|
|
677
|
-
const appTsx = `import { BrowserRouter, Routes, Route
|
|
746
|
+
const appTsx = `import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
678
747
|
import { SchemaRenderer } from '@object-ui/react';
|
|
679
748
|
import '@object-ui/components';
|
|
680
749
|
import '@object-ui/plugin-charts';
|
|
@@ -700,202 +769,20 @@ ${routeComponents.join("\n")}
|
|
|
700
769
|
}
|
|
701
770
|
|
|
702
771
|
export default App;`;
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
--background: 0 0% 100%;
|
|
711
|
-
--foreground: 222.2 84% 4.9%;
|
|
712
|
-
--card: 0 0% 100%;
|
|
713
|
-
--card-foreground: 222.2 84% 4.9%;
|
|
714
|
-
--popover: 0 0% 100%;
|
|
715
|
-
--popover-foreground: 222.2 84% 4.9%;
|
|
716
|
-
--primary: 222.2 47.4% 11.2%;
|
|
717
|
-
--primary-foreground: 210 40% 98%;
|
|
718
|
-
--secondary: 210 40% 96.1%;
|
|
719
|
-
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
720
|
-
--muted: 210 40% 96.1%;
|
|
721
|
-
--muted-foreground: 215.4 16.3% 46.9%;
|
|
722
|
-
--accent: 210 40% 96.1%;
|
|
723
|
-
--accent-foreground: 222.2 47.4% 11.2%;
|
|
724
|
-
--destructive: 0 84.2% 60.2%;
|
|
725
|
-
--destructive-foreground: 210 40% 98%;
|
|
726
|
-
--border: 214.3 31.8% 91.4%;
|
|
727
|
-
--input: 214.3 31.8% 91.4%;
|
|
728
|
-
--ring: 222.2 84% 4.9%;
|
|
729
|
-
--radius: 0.5rem;
|
|
730
|
-
--chart-1: 12 76% 61%;
|
|
731
|
-
--chart-2: 173 58% 39%;
|
|
732
|
-
--chart-3: 197 37% 24%;
|
|
733
|
-
--chart-4: 43 74% 66%;
|
|
734
|
-
--chart-5: 27 87% 67%;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
.dark {
|
|
738
|
-
--background: 222.2 84% 4.9%;
|
|
739
|
-
--foreground: 210 40% 98%;
|
|
740
|
-
--card: 222.2 84% 4.9%;
|
|
741
|
-
--card-foreground: 210 40% 98%;
|
|
742
|
-
--popover: 222.2 84% 4.9%;
|
|
743
|
-
--popover-foreground: 210 40% 98%;
|
|
744
|
-
--primary: 210 40% 98%;
|
|
745
|
-
--primary-foreground: 222.2 47.4% 11.2%;
|
|
746
|
-
--secondary: 217.2 32.6% 17.5%;
|
|
747
|
-
--secondary-foreground: 210 40% 98%;
|
|
748
|
-
--muted: 217.2 32.6% 17.5%;
|
|
749
|
-
--muted-foreground: 215 20.2% 65.1%;
|
|
750
|
-
--accent: 217.2 32.6% 17.5%;
|
|
751
|
-
--accent-foreground: 210 40% 98%;
|
|
752
|
-
--destructive: 0 62.8% 30.6%;
|
|
753
|
-
--destructive-foreground: 210 40% 98%;
|
|
754
|
-
--border: 217.2 32.6% 17.5%;
|
|
755
|
-
--input: 217.2 32.6% 17.5%;
|
|
756
|
-
--ring: 212.7 26.8% 83.9%;
|
|
757
|
-
--chart-1: 220 70% 50%;
|
|
758
|
-
--chart-2: 160 60% 45%;
|
|
759
|
-
--chart-3: 30 80% 55%;
|
|
760
|
-
--chart-4: 280 65% 60%;
|
|
761
|
-
--chart-5: 340 75% 55%;
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
@layer base {
|
|
766
|
-
* {
|
|
767
|
-
@apply border-border;
|
|
768
|
-
}
|
|
769
|
-
body {
|
|
770
|
-
@apply bg-background text-foreground font-sans antialiased min-h-screen;
|
|
771
|
-
}
|
|
772
|
-
}`;
|
|
773
|
-
writeFileSync(join(srcDir, "index.css"), indexCss);
|
|
774
|
-
const cwd = process.cwd();
|
|
775
|
-
const isMonorepo = existsSync(join(cwd, "pnpm-workspace.yaml"));
|
|
776
|
-
const contentPaths = ["'./index.html'", "'./src/**/*.{js,ts,jsx,tsx,json}'"];
|
|
777
|
-
if (isMonorepo) {
|
|
778
|
-
const componentsPath = join(cwd, "packages/components/src/**/*.{ts,tsx}");
|
|
779
|
-
const pluginsPath = join(cwd, "packages/plugin-*/src/**/*.{ts,tsx}");
|
|
780
|
-
contentPaths.push(`'${componentsPath}'`);
|
|
781
|
-
contentPaths.push(`'${pluginsPath}'`);
|
|
782
|
-
}
|
|
783
|
-
const tailwindConfig = `/** @type {import('tailwindcss').Config} */
|
|
784
|
-
export default {
|
|
785
|
-
darkMode: ['class'],
|
|
786
|
-
content: [${contentPaths.join(", ")}],
|
|
787
|
-
theme: {
|
|
788
|
-
extend: {
|
|
789
|
-
borderRadius: {
|
|
790
|
-
lg: 'var(--radius)',
|
|
791
|
-
md: 'calc(var(--radius) - 2px)',
|
|
792
|
-
sm: 'calc(var(--radius) - 4px)',
|
|
793
|
-
},
|
|
794
|
-
colors: {
|
|
795
|
-
background: 'hsl(var(--background))',
|
|
796
|
-
foreground: 'hsl(var(--foreground))',
|
|
797
|
-
card: {
|
|
798
|
-
DEFAULT: 'hsl(var(--card))',
|
|
799
|
-
foreground: 'hsl(var(--card-foreground))',
|
|
800
|
-
},
|
|
801
|
-
popover: {
|
|
802
|
-
DEFAULT: 'hsl(var(--popover))',
|
|
803
|
-
foreground: 'hsl(var(--popover-foreground))',
|
|
804
|
-
},
|
|
805
|
-
primary: {
|
|
806
|
-
DEFAULT: 'hsl(var(--primary))',
|
|
807
|
-
foreground: 'hsl(var(--primary-foreground))',
|
|
808
|
-
},
|
|
809
|
-
secondary: {
|
|
810
|
-
DEFAULT: 'hsl(var(--secondary))',
|
|
811
|
-
foreground: 'hsl(var(--secondary-foreground))',
|
|
812
|
-
},
|
|
813
|
-
muted: {
|
|
814
|
-
DEFAULT: 'hsl(var(--muted))',
|
|
815
|
-
foreground: 'hsl(var(--muted-foreground))',
|
|
816
|
-
},
|
|
817
|
-
accent: {
|
|
818
|
-
DEFAULT: 'hsl(var(--accent))',
|
|
819
|
-
foreground: 'hsl(var(--accent-foreground))',
|
|
820
|
-
},
|
|
821
|
-
destructive: {
|
|
822
|
-
DEFAULT: 'hsl(var(--destructive))',
|
|
823
|
-
foreground: 'hsl(var(--destructive-foreground))',
|
|
824
|
-
},
|
|
825
|
-
border: 'hsl(var(--border))',
|
|
826
|
-
input: 'hsl(var(--input))',
|
|
827
|
-
ring: 'hsl(var(--ring))',
|
|
828
|
-
chart: {
|
|
829
|
-
1: 'hsl(var(--chart-1))',
|
|
830
|
-
2: 'hsl(var(--chart-2))',
|
|
831
|
-
3: 'hsl(var(--chart-3))',
|
|
832
|
-
4: 'hsl(var(--chart-4))',
|
|
833
|
-
5: 'hsl(var(--chart-5))',
|
|
834
|
-
},
|
|
835
|
-
},
|
|
836
|
-
},
|
|
837
|
-
},
|
|
838
|
-
plugins: [],
|
|
839
|
-
};`;
|
|
840
|
-
writeFileSync(join(tmpDir, "tailwind.config.js"), tailwindConfig);
|
|
841
|
-
const postcssConfig = `export default {
|
|
842
|
-
plugins: {
|
|
843
|
-
tailwindcss: {},
|
|
844
|
-
autoprefixer: {},
|
|
845
|
-
},
|
|
846
|
-
};`;
|
|
847
|
-
writeFileSync(join(tmpDir, "postcss.config.js"), postcssConfig);
|
|
848
|
-
const packageJson = {
|
|
849
|
-
name: "objectui-temp-app",
|
|
850
|
-
private: true,
|
|
851
|
-
type: "module",
|
|
852
|
-
dependencies: {
|
|
853
|
-
react: "^18.3.1",
|
|
854
|
-
"react-dom": "^18.3.1",
|
|
855
|
-
"react-router-dom": "^7.12.0",
|
|
856
|
-
"@object-ui/react": "^0.1.0",
|
|
857
|
-
"@object-ui/components": "^0.1.0"
|
|
858
|
-
},
|
|
859
|
-
devDependencies: {
|
|
860
|
-
"@types/react": "^18.3.12",
|
|
861
|
-
"@types/react-dom": "^18.3.1",
|
|
862
|
-
"@vitejs/plugin-react": "^4.2.1",
|
|
863
|
-
autoprefixer: "^10.4.23",
|
|
864
|
-
postcss: "^8.5.6",
|
|
865
|
-
tailwindcss: "^3.4.19",
|
|
866
|
-
typescript: "~5.7.3",
|
|
867
|
-
vite: "^5.0.0"
|
|
868
|
-
}
|
|
869
|
-
};
|
|
870
|
-
writeFileSync(join(tmpDir, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
871
|
-
const tsconfig = {
|
|
872
|
-
compilerOptions: {
|
|
873
|
-
target: "ES2020",
|
|
874
|
-
useDefineForClassFields: true,
|
|
875
|
-
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
876
|
-
module: "ESNext",
|
|
877
|
-
skipLibCheck: true,
|
|
878
|
-
moduleResolution: "bundler",
|
|
879
|
-
allowImportingTsExtensions: true,
|
|
880
|
-
resolveJsonModule: true,
|
|
881
|
-
isolatedModules: true,
|
|
882
|
-
noEmit: true,
|
|
883
|
-
jsx: "react-jsx",
|
|
884
|
-
strict: true,
|
|
885
|
-
noUnusedLocals: true,
|
|
886
|
-
noUnusedParameters: true,
|
|
887
|
-
noFallthroughCasesInSwitch: true
|
|
888
|
-
},
|
|
889
|
-
include: ["src"]
|
|
890
|
-
};
|
|
891
|
-
writeFileSync(join(tmpDir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
|
|
772
|
+
files["src/App.tsx"] = appTsx;
|
|
773
|
+
files["src/vite-env.d.ts"] = APP_VITE_ENV_D_TS;
|
|
774
|
+
files["src/index.css"] = buildAppIndexCss(context);
|
|
775
|
+
files["postcss.config.js"] = APP_POSTCSS_CONFIG;
|
|
776
|
+
files["package.json"] = JSON.stringify(buildRoutedAppPackageJson(), null, 2);
|
|
777
|
+
files["tsconfig.json"] = JSON.stringify(APP_TSCONFIG, null, 2);
|
|
778
|
+
return files;
|
|
892
779
|
}
|
|
893
780
|
|
|
894
781
|
// src/commands/serve.ts
|
|
895
782
|
async function serve(schemaPath, options) {
|
|
896
783
|
const cwd = process.cwd();
|
|
897
|
-
const pagesDir =
|
|
898
|
-
const hasPagesDir =
|
|
784
|
+
const pagesDir = join3(cwd, "pages");
|
|
785
|
+
const hasPagesDir = existsSync3(pagesDir);
|
|
899
786
|
let routes = [];
|
|
900
787
|
let schema = null;
|
|
901
788
|
let useFileSystemRouting = false;
|
|
@@ -912,7 +799,7 @@ async function serve(schemaPath, options) {
|
|
|
912
799
|
});
|
|
913
800
|
} else {
|
|
914
801
|
const fullSchemaPath = resolve(cwd, schemaPath);
|
|
915
|
-
if (!
|
|
802
|
+
if (!existsSync3(fullSchemaPath)) {
|
|
916
803
|
throw new Error(`Schema file not found: ${schemaPath}
|
|
917
804
|
Run 'objectui init' to create a sample schema.`);
|
|
918
805
|
}
|
|
@@ -923,7 +810,7 @@ Run 'objectui init' to create a sample schema.`);
|
|
|
923
810
|
throw new Error(`Invalid schema file: ${error instanceof Error ? error.message : error}`);
|
|
924
811
|
}
|
|
925
812
|
}
|
|
926
|
-
const tmpDir =
|
|
813
|
+
const tmpDir = join3(cwd, ".objectui-tmp");
|
|
927
814
|
mkdirSync2(tmpDir, { recursive: true });
|
|
928
815
|
if (useFileSystemRouting) {
|
|
929
816
|
createTempAppWithRouting(tmpDir, routes);
|
|
@@ -967,8 +854,8 @@ Run 'objectui init' to create a sample schema.`);
|
|
|
967
854
|
}
|
|
968
855
|
|
|
969
856
|
// src/commands/init.ts
|
|
970
|
-
import { existsSync as
|
|
971
|
-
import { join as
|
|
857
|
+
import { existsSync as existsSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
|
|
858
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
972
859
|
import chalk3 from "chalk";
|
|
973
860
|
var templates = {
|
|
974
861
|
simple: {
|
|
@@ -1312,29 +1199,35 @@ var templates = {
|
|
|
1312
1199
|
]
|
|
1313
1200
|
}
|
|
1314
1201
|
};
|
|
1315
|
-
|
|
1316
|
-
const
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1202
|
+
function buildInitPackageJson(name) {
|
|
1203
|
+
const platformRange = platformPackageRange();
|
|
1204
|
+
return {
|
|
1205
|
+
name,
|
|
1206
|
+
version: "0.1.0",
|
|
1207
|
+
private: true,
|
|
1208
|
+
type: "module",
|
|
1209
|
+
scripts: {
|
|
1210
|
+
dev: "vite",
|
|
1211
|
+
build: "tsc && vite build",
|
|
1212
|
+
preview: "vite preview"
|
|
1213
|
+
},
|
|
1214
|
+
dependencies: {
|
|
1215
|
+
"@object-ui/components": platformRange,
|
|
1216
|
+
"@object-ui/react": platformRange,
|
|
1217
|
+
react: REACT_RANGE,
|
|
1218
|
+
"react-dom": REACT_RANGE
|
|
1219
|
+
},
|
|
1220
|
+
devDependencies: { ...SCAFFOLD_DEV_DEPENDENCIES }
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
function buildInitFiles(name, templateName) {
|
|
1224
|
+
const template = templates[templateName];
|
|
1329
1225
|
if (!template) {
|
|
1330
1226
|
throw new Error(
|
|
1331
|
-
`Unknown template: ${
|
|
1227
|
+
`Unknown template: ${templateName}
|
|
1332
1228
|
Available templates: ${Object.keys(templates).join(", ")}`
|
|
1333
1229
|
);
|
|
1334
1230
|
}
|
|
1335
|
-
const schemaPath = join3(targetDir, "app.json");
|
|
1336
|
-
writeFileSync2(schemaPath, JSON.stringify(template, null, 2));
|
|
1337
|
-
console.log(chalk3.green("\u2713 Created app.json"));
|
|
1338
1231
|
const readme = `# ${name}
|
|
1339
1232
|
|
|
1340
1233
|
An Object UI application built from JSON schemas.
|
|
@@ -1377,46 +1270,12 @@ Edit \`app.json\` to customize your application. The dev server will automatical
|
|
|
1377
1270
|
|
|
1378
1271
|
Built with \u2764\uFE0F using [Object UI](https://www.objectui.org)
|
|
1379
1272
|
`;
|
|
1380
|
-
writeFileSync2(join3(targetDir, "README.md"), readme);
|
|
1381
|
-
console.log(chalk3.green("\u2713 Created README.md"));
|
|
1382
1273
|
const gitignore = `.objectui-tmp
|
|
1383
1274
|
node_modules
|
|
1384
1275
|
dist
|
|
1385
1276
|
.DS_Store
|
|
1386
1277
|
*.log
|
|
1387
1278
|
`;
|
|
1388
|
-
writeFileSync2(join3(targetDir, ".gitignore"), gitignore);
|
|
1389
|
-
console.log(chalk3.green("\u2713 Created .gitignore"));
|
|
1390
|
-
const packageJson = {
|
|
1391
|
-
name,
|
|
1392
|
-
version: "0.1.0",
|
|
1393
|
-
private: true,
|
|
1394
|
-
type: "module",
|
|
1395
|
-
scripts: {
|
|
1396
|
-
dev: "vite",
|
|
1397
|
-
build: "tsc && vite build",
|
|
1398
|
-
preview: "vite preview"
|
|
1399
|
-
},
|
|
1400
|
-
dependencies: {
|
|
1401
|
-
"@object-ui/components": "^2.0.0",
|
|
1402
|
-
"@object-ui/react": "^2.0.0",
|
|
1403
|
-
react: "^19.2.0",
|
|
1404
|
-
"react-dom": "^19.2.0"
|
|
1405
|
-
},
|
|
1406
|
-
devDependencies: {
|
|
1407
|
-
"@tailwindcss/postcss": "^4.1.18",
|
|
1408
|
-
"@types/react": "^19.2.13",
|
|
1409
|
-
"@types/react-dom": "^19.2.6",
|
|
1410
|
-
"@vitejs/plugin-react": "^5.1.3",
|
|
1411
|
-
autoprefixer: "^10.4.23",
|
|
1412
|
-
postcss: "^8.5.6",
|
|
1413
|
-
tailwindcss: "^4.1.18",
|
|
1414
|
-
typescript: "^5.9.3",
|
|
1415
|
-
vite: "^7.3.1"
|
|
1416
|
-
}
|
|
1417
|
-
};
|
|
1418
|
-
writeFileSync2(join3(targetDir, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
1419
|
-
console.log(chalk3.green("\u2713 Created package.json"));
|
|
1420
1279
|
const viteConfig = `import { defineConfig } from 'vite';
|
|
1421
1280
|
import react from '@vitejs/plugin-react';
|
|
1422
1281
|
|
|
@@ -1427,15 +1286,6 @@ export default defineConfig({
|
|
|
1427
1286
|
},
|
|
1428
1287
|
});
|
|
1429
1288
|
`;
|
|
1430
|
-
writeFileSync2(join3(targetDir, "vite.config.ts"), viteConfig);
|
|
1431
|
-
console.log(chalk3.green("\u2713 Created vite.config.ts"));
|
|
1432
|
-
const tailwindConfig = `/** @type {import('tailwindcss').Config} */
|
|
1433
|
-
export default {
|
|
1434
|
-
content: ['./index.html', './src/**/*.{ts,tsx}'],
|
|
1435
|
-
};
|
|
1436
|
-
`;
|
|
1437
|
-
writeFileSync2(join3(targetDir, "tailwind.config.js"), tailwindConfig);
|
|
1438
|
-
console.log(chalk3.green("\u2713 Created tailwind.config.js"));
|
|
1439
1289
|
const postcssConfig = `export default {
|
|
1440
1290
|
plugins: {
|
|
1441
1291
|
'@tailwindcss/postcss': {},
|
|
@@ -1443,8 +1293,6 @@ export default {
|
|
|
1443
1293
|
},
|
|
1444
1294
|
};
|
|
1445
1295
|
`;
|
|
1446
|
-
writeFileSync2(join3(targetDir, "postcss.config.js"), postcssConfig);
|
|
1447
|
-
console.log(chalk3.green("\u2713 Created postcss.config.js"));
|
|
1448
1296
|
const indexHtml = `<!doctype html>
|
|
1449
1297
|
<html lang="en">
|
|
1450
1298
|
<head>
|
|
@@ -1458,14 +1306,9 @@ export default {
|
|
|
1458
1306
|
</body>
|
|
1459
1307
|
</html>
|
|
1460
1308
|
`;
|
|
1461
|
-
writeFileSync2(join3(targetDir, "index.html"), indexHtml);
|
|
1462
|
-
console.log(chalk3.green("\u2713 Created index.html"));
|
|
1463
|
-
const srcDir = join3(targetDir, "src");
|
|
1464
|
-
mkdirSync3(srcDir, { recursive: true });
|
|
1465
1309
|
const indexCss = `@import 'tailwindcss';
|
|
1310
|
+
@import '@object-ui/components/style.css';
|
|
1466
1311
|
`;
|
|
1467
|
-
writeFileSync2(join3(srcDir, "index.css"), indexCss);
|
|
1468
|
-
console.log(chalk3.green("\u2713 Created src/index.css"));
|
|
1469
1312
|
const mainTsx = `import { StrictMode } from 'react';
|
|
1470
1313
|
import { createRoot } from 'react-dom/client';
|
|
1471
1314
|
import App from './App';
|
|
@@ -1477,17 +1320,18 @@ createRoot(document.getElementById('root')!).render(
|
|
|
1477
1320
|
</StrictMode>,
|
|
1478
1321
|
);
|
|
1479
1322
|
`;
|
|
1480
|
-
writeFileSync2(join3(srcDir, "main.tsx"), mainTsx);
|
|
1481
|
-
console.log(chalk3.green("\u2713 Created src/main.tsx"));
|
|
1482
1323
|
const appTsx = `import { SchemaRenderer } from '@object-ui/react';
|
|
1324
|
+
// Registers the component renderers SchemaRenderer looks up. Side-effect
|
|
1325
|
+
// import \u2014 removing it makes every node render "Unknown component type".
|
|
1326
|
+
import '@object-ui/components';
|
|
1483
1327
|
import schema from '../app.json';
|
|
1484
1328
|
|
|
1485
1329
|
export default function App() {
|
|
1486
1330
|
return <SchemaRenderer schema={schema} />;
|
|
1487
1331
|
}
|
|
1488
1332
|
`;
|
|
1489
|
-
|
|
1490
|
-
|
|
1333
|
+
const viteEnvDts = `/// <reference types="vite/client" />
|
|
1334
|
+
`;
|
|
1491
1335
|
const tsconfig = {
|
|
1492
1336
|
compilerOptions: {
|
|
1493
1337
|
target: "ES2020",
|
|
@@ -1509,8 +1353,42 @@ export default function App() {
|
|
|
1509
1353
|
},
|
|
1510
1354
|
include: ["src"]
|
|
1511
1355
|
};
|
|
1512
|
-
|
|
1513
|
-
|
|
1356
|
+
return {
|
|
1357
|
+
"app.json": JSON.stringify(template, null, 2),
|
|
1358
|
+
"README.md": readme,
|
|
1359
|
+
".gitignore": gitignore,
|
|
1360
|
+
"package.json": JSON.stringify(buildInitPackageJson(name), null, 2),
|
|
1361
|
+
"vite.config.ts": viteConfig,
|
|
1362
|
+
"postcss.config.js": postcssConfig,
|
|
1363
|
+
"index.html": indexHtml,
|
|
1364
|
+
"src/index.css": indexCss,
|
|
1365
|
+
"src/main.tsx": mainTsx,
|
|
1366
|
+
"src/App.tsx": appTsx,
|
|
1367
|
+
"src/vite-env.d.ts": viteEnvDts,
|
|
1368
|
+
"tsconfig.json": JSON.stringify(tsconfig, null, 2)
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
async function init(name, options) {
|
|
1372
|
+
const cwd = process.cwd();
|
|
1373
|
+
const projectDir = join4(cwd, name);
|
|
1374
|
+
if (existsSync4(projectDir) && name !== ".") {
|
|
1375
|
+
throw new Error(`Directory "${name}" already exists. Please choose a different name.`);
|
|
1376
|
+
}
|
|
1377
|
+
const targetDir = name === "." ? cwd : projectDir;
|
|
1378
|
+
if (name !== ".") {
|
|
1379
|
+
mkdirSync3(projectDir, { recursive: true });
|
|
1380
|
+
}
|
|
1381
|
+
console.log(chalk3.blue("\u{1F3A8} Creating Object UI application..."));
|
|
1382
|
+
console.log(chalk3.dim(` Template: ${options.template}`));
|
|
1383
|
+
console.log();
|
|
1384
|
+
for (const [relativePath, contents] of Object.entries(
|
|
1385
|
+
buildInitFiles(name, options.template)
|
|
1386
|
+
)) {
|
|
1387
|
+
const target = join4(targetDir, relativePath);
|
|
1388
|
+
mkdirSync3(dirname3(target), { recursive: true });
|
|
1389
|
+
writeFileSync2(target, contents);
|
|
1390
|
+
console.log(chalk3.green(`\u2713 Created ${relativePath}`));
|
|
1391
|
+
}
|
|
1514
1392
|
console.log();
|
|
1515
1393
|
console.log(chalk3.green("\u2728 Application created successfully!"));
|
|
1516
1394
|
console.log();
|
|
@@ -1534,4 +1412,4 @@ export {
|
|
|
1534
1412
|
serve,
|
|
1535
1413
|
init
|
|
1536
1414
|
};
|
|
1537
|
-
//# sourceMappingURL=chunk-
|
|
1415
|
+
//# sourceMappingURL=chunk-2MZA766D.js.map
|